Execution authority, permission, and sandbox
This is the canonical engineering contract for request identity, tool approvals, live permission changes, and local process isolation. It covers Web, CLI, ACP, channels, nested Agents, scheduled tasks, and continuation. Permission changes do not redesign host isolation or add speculative capability tiers.
One operation decision
The approval manifest and execution wrapper use the same policy decision. Order: hard constraints, authority, plan restrictions, explicit deny, explicit ask or mandatory approval, exact Web Use grant, bypass, explicit allow, scheduled Memory exception, safe reads, acceptEdits, Auto classification, ordinary approval. Non-interactive requests that require approval return a denial. Owner-delegated Agent shell and managed-process operations use the admitted permission snapshot rather than a blanket source prohibition. MCP callers and non-owner spawned Agents retain that prohibition; worktree controls retain their separate restriction.
Bypass skips ordinary approval and Auto classification. It does not override explicit ask/deny, mandatory approvals for plan exit or self-update, plugin tool gates, or Sandbox. Invalid mode values are rejected by configuration commands. Denials identify their reason and capability without exposing secrets.
Web decision submission retains the question and selected answer until the canonical wait command is acknowledged as applied. Unknown delivery locks the selection and retries the same command identifier; a socket send alone is not completion. This applies to approvals, ordinary questions and forms as well as discussion.
Delegated permission checks and audit privacy
Spawned-Agent and MCP write/edit calls require a nonblank string target. An explicit empty patch target is denied before bypass and allow rules. Relative targets are resolved against the bound worktree; realpath containment includes file and parent-directory symlinks. The shared file-safety helper retains its existing current-directory semantics for standalone relative inputs.
Delegated risky-tool checks admitted by bypass or an allow rule emit security.risky_tool_delegated; denied write targets emit security.path_violation. These events describe permission checks, not completed tool execution, and may repeat during manifest construction or reconciliation. The payload contains only session, tool, source, authority and a fixed reason where applicable. Commands, code, target paths and all other argument text are omitted. The origin is system; session metadata uses the existing event-log routing and rotation. Event delivery is best effort and does not authorize or block an operation.
Permission modes
| Mode | Behavior |
|---|---|
| ask | Safe reads proceed; other operations require approval. |
| acceptEdits | Safe supported edits inside working roots proceed; commands still require approval. |
| plan | Only the existing read-only plan tool policy is allowed. |
| auto | Safe tools proceed; risky tools or classifier denials are blocked. |
| bypass | Ordinary approvals and Auto classification are skipped. |
Session settings take precedence over project defaults, then ask. The effective resolved mode is used for actual admission and UI acknowledgements.
Versioned live permission lifecycle
The existing SessionStore owns a versioned permission_state dictionary. Atomic compare-and-set prevents stale clients from overwriting a newer selection. State includes mode and owner principal. The WebSocket settings command authenticates the owner, validates session scope, and returns the authoritative mode and version. No parallel approval database or generic policy engine is introduced.
Interactive local requests read their principal-bound permission state at each tool approval check. One call retains that decision through dispatch; already authorized calls are not interrupted. Immutable admission input and continuation contracts remain unchanged. At trusted Agent spawn admission, a running owner parent passes its effective permission mode and explicit rules into the child’s immutable input, bound to the same owner principal and the exact runtime parent. A local interactive parent resolves its latest confirmed mode before that snapshot is taken; a nested non-interactive parent passes its already frozen snapshot. Existing child inputs are not rewritten. Standalone scheduled tasks, paired channels, and unrelated sessions cannot adopt these live overrides. Spawned Agents remain non-interactive: explicit ask and mandatory approval still deny when no approver is available, while inherited bypass skips only ordinary approval. Authority and Sandbox remain independent constraints.
On a mode change, open ordinary permission approvals are re-evaluated using the shared decision. An operation now allowed is resolved through the existing canonical wait-answer command and resumed from its checkpoint. Explicit ask, mandatory approval, Sandbox escalation, and user questions remain waiting. A wait published concurrently with a settings change performs the same recheck after the old runtime releases its cancellation token. Startup recovery also re-evaluates persisted mode changes. Expired, cancelled, or completed work is never resurrected.
The UI distinguishes a requested selection from an acknowledged mode. Updates carry a version; older acknowledgements and hydration snapshots cannot replace newer state. Transport errors remain visible. An unsent draft stores its selection locally without creating an empty session; initial submission supplies it. Existing sessions use confirmed server state.
Plan restrictions are enforced at the tool boundary so switching into plan blocks writes already proposed by the model. Keeping the tool catalog stable permits switching out of plan during a running turn without invalidating continuation. Model-entered plan state still requires its approved exit operation.
The Web and installed App send a mode change immediately with the session version already confirmed by the server; they read first only when no version is known. Confirmation is the effective boundary, independent of an in-flight model request. After confirmation, each subsequent ordinary tool approval check uses the new mode, including later calls in the same generated batch. No model restart or next user message is required. Version conflicts remain errors; the UI never displays an unconfirmed change as effective.
Tool and host boundaries
File tools apply in-process guards. Local subprocesses use Seatbelt on macOS or bubblewrap on Linux. Browser/Web Use uses an exact surface grant. Docker and SSH use their own execution boundary; configured MCP processes are owner-configured trust and are not described as local sandbox isolation.
workspace-write allows working roots, masks protected reads, filters credential environment variables, and disables network by default. danger-full-access uses host user permissions. Missing sandbox backends refuse by default; explicit warn is an acknowledged fallback. Auto-imported agentic application paths retain hard write restrictions.
Sandbox is a session override resolved into an immutable turn snapshot. Changing its switch affects subsequent turns, not current processes, other sessions, scheduled tasks, or inherited child policy. Ordinary approval never disables Sandbox. Bypass does not offer automatic sandbox escalation.
Sandbox escalation
A structured sandbox denial can request an exact retry only from an interactive local owner with approval.request. Approved escalation lifts configurable restrictions while retaining protected application paths and credential filtering. always_path adds only the specific permissible read path. An approval is bound to its session, execution, tool, and tool call. A normal tool approval cannot authorize a sandbox escalation. The current execution protocol has no post-tool escalation wait; such denials require an explicit settings change and a new call, and cannot silently reuse the ordinary approval. A second failure is returned without another retry. Paired channels, MCP clients, cron, and subagents cannot escalate.
Reference corpus and choices
| Framework | Adopted or adapted | Boundary |
|---|---|---|
| Claude Code | Permission modes, independent Sandbox, Auto classification | Keep authority and explicit rules ahead of bypass; a full background-classifier UX remains future work. |
| Codex CLI | Structured violations and exact approved retry | Per-tool sandbox override is not implemented. |
| OpenClaw | Credential filtering, backend refusal, nested tool classification | No automatic Docker selection. |
| Hermes Agent | Hard rules before bypass, command normalization, non-interactive refusal | Normalize NFKC, ANSI, NUL, and environment wrappers. |
| OpenCode | Per-tool and per-resource permission rules | Permission is not OS isolation. |
| pi-mono | Extension interception and fail-closed non-interactive behavior | Reject silent project overrides of global security constraints. |
| Aider | Git recovery as a separate facility | Recovery does not replace credential, network, or process boundaries. |
| Goose / WeClaw adapters | Explicit backend distinctions | Reject external automatic owner approvals and optional isolation presented as default. |
These are retained design comparisons, not newly verified claims about the latest upstream versions.
Verified permission comparisons
Claude Code permissions documents deny-before-ask-before-allow, live rule changes at the next tool call, and comments attached to individual approvals or denials. OpenProgram retains explicit rule precedence and same-session discussion, but does not implement approval comments that execute first and deliver feedback afterward.
OpenCode V2 permissions uses last-match ordering, project-scoped saved patterns and same-session rejection fan-out. OpenProgram intentionally retains deny-first ordering, exact-operation grants and a single canonical wait target. OpenCode V2 subagents use their own policies; OpenProgram bounds child admission by parent identity and its permission snapshot. These are deliberate differences, not missing equivalents.
Current audit repairs require acknowledged answers, matching execution versions after reload and service-owned allowed scopes. One-shot self-update approvals and operations without a representable exact rule expose only once. Canonical validation enforces the same scope list. Runtime acceptance of these repairs remains pending.
OpenAI on Codex operation separates sandbox enforcement from approval policy, supports single-action and session-level approval, and describes managed constraints plus approval telemetry. OpenProgram preserves that separation, but its remembered operation rule is project-scoped rather than session-scoped. Domain policy, managed enterprise enforcement and remote audit export are not equivalent capabilities in OpenProgram and remain explicit limitations.
Failures and compatibility
Missing authority, stale settings versions, invalid modes, denied capability, explicit rules, classifier failure, and sandbox refusal remain distinguishable. No failure silently becomes owner or bypass. Existing stored permission_mode is readable when no versioned state exists. New authenticated submissions attach fresh authority; legacy admitted requests without authority must be resubmitted through an authenticated entry rather than elevated during recovery.
Host process visibility may prevent ps, top, or lsof; Docker sockets are not exposed automatically. Linux wildcard masking has limitations. Domain/port network allowlists require a managed proxy and redirect checks and remain unimplemented. Browser and remote networking have separate controls.
Files and acceptance boundaries
| Module | Responsibility |
|---|---|
| agent/authority.py | Identity and capability ceilings |
| agent/permissions/state.py | Versioned session state, owner validation and atomic updates |
| agent/permissions/policy.py | Shared operation decisions, explicit rules and hard constraints |
| agent/permissions/classifier.py | Auto risk classification; only explicit JSON boolean true permits execution |
| agent/permissions/approval.py | Approval manifests, exact wait consumption and tool execution |
| agent/permissions/lifecycle.py | Live call snapshots and canonical wait reconciliation |
| agent/session_config.py | Legacy and current settings resolution |
| agent/production_driver.py | Durable admission, immutable recovery, wait publication |
| server WebSocket permission handler | Authenticated settings and canonical wait re-evaluation |
| Web permission state and composer | Confirmed mode, pending/error feedback, ordered hydration |
Acceptance exercises actual chat admission and a safe tool; inherited bypass; running ask-to-bypass and bypass-to-ask; waiting approval continuation; explicit ask/deny and forced approvals; plan transitions; owner/session isolation; stale versions; reload/reconnect; and unchanged Sandbox denial.
Portable approved file writes
Approved edit, write and apply_patch operations share file_state.write_checked. The dispatcher and this module import on Windows without Unix-only modules. File locking uses the existing compatibility adapter; files are opened in binary mode and POSIX retains O_NOFOLLOW.
The writer checks the approved content and identity, opens without truncation, takes the exclusive lock, hashes the opened descriptor and rechecks the pathname identity and resolved destination before mutation. Path revalidation uses metadata rather than a second read handle: Windows byte locks can deny reads through another handle in the same process. Symlinks and reparse entries are rejected. Exclusive creation protects targets approved as missing. The path fallback detects replacements before writing but does not claim descriptor-relative protection against every concurrent ancestor replacement.
Acceptance covers dispatcher import without fcntl, changed or deleted targets, existing and newly created files, exact UTF-8 bytes, replacement/link races and repeated writes. The native Windows installation smoke imports the dispatcher, and platform CI runs the approval regression tests before the full unit suite.
Reference: Python fcntl is Unix-only; msvcrt byte locking provides the existing Windows adapter. Reusing that adapter avoids a second lock implementation; removing all link checks or silently skipping locking does not satisfy the contract.
Implementation status
The portable approved-file implementation passes independent specification and quality reviews and the focused local regression checks. Native Windows x64 and arm64 execution is pending; the platform CI selection includes the shared writer and public dispatcher regressions. This scoped evidence does not establish full Windows release or installed-App acceptance.
The current audit covers policy precedence, principal-bound live settings, approval scope enforcement, all Web answer entry points, reconnect projections, keyboard navigation and the official Claude Code, Codex and OpenCode comparisons. TypeScript checking, Python syntax checking and documentation link checking pass. No full repository test suite or new independent-agent review is claimed.
| Boundary | Evidence | Remaining limit |
|---|---|---|
| Approval recovery | The installed App restores an approval after reload; single-use approval completes the requested printf operation. | Does not prove every platform sandbox backend. |
| Scope and decline | Options match before and after reload. Decline terminates the execution with no managed process started. | Permanent rule-save failure is reviewed in code; filesystem failure injection is not performed. |
| Question delivery | All composer presentations use the same acknowledged submit hook. The question tool declares its durable wait before execution. | End-to-end acceptance of the new question declaration is pending: one model request remains in flight and a separate request generated an unrelated tool call, which was denied. |
| Policy and lifecycle | Shared policy and canonical reconciliation preserve explicit rules, mandatory waits, identity bounds and version checks. | These boundaries are source-reviewed here; the current audit does not claim to rerun every historical lifecycle regression. |
Existing host isolation is retained. Domain allowlists, resource quotas, Windows sandbox support, per-tool sandbox overrides and a complete background Auto-classifier interface remain explicit product limitations. The audit is not complete until question acceptance and final installation are verified.