feat(zed): add a zed permissions override for sandbox_permissions and profiles - #2643
Merged
Merged
Conversation
… profiles Zed 1.14.2 turns OS-level agent sandboxing on by default for the terminal and fetch tools, so most setups now need to relax agent.sandbox_permissions - none of which was authorable from .rulesync/permissions.jsonc, since zed was bound to the generic override schema. agent.profiles, the separate tool-availability layer, was equally out of reach. Both are now verbatim passthrough blocks on a new ZedPermissionsOverride schema, written into agent and lifted back out on import. The translator reads only those two keys by name, and warns on a tool_permissions key, so an override can never weaken a canonical deny.
The allowlist made an unsupported or misspelled key inert, but silently - so `zed.sandboxPermissions` looked like it worked. Report every key the patch does not consume, and document why the block is an allowlist rather than a verbatim agent merge: `agent.always_allow_tool_actions` would disarm every permission rule at once if the override could reach it. Also record the scope rationale in the docs. Zed layers user settings under project settings and applies a project's .zed/settings.json once the worktree is trusted, so both scopes are written - and a project-scoped allow_unsandboxed is a real grant, which is worth saying out loud.
agent.sandbox_permissions is not only hand-written: Zed saves an always-allow clicked in the sandbox prompt there. So an import can pick up an ad-hoc grant from one machine and a later generate ships it to the whole team via the project file. Say so, along with the mirror case where regenerating discards approvals Zed recorded after the override was authored.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #2415 (gap 5
sandbox_permissions+profilespassthrough per the 2026-08-06 comment).Background
Zed 1.14.2 (2026-08-05) turned OS-level agent sandboxing on by default for the
terminalandfetchtools. The defaults forbid network access, writing outside the project directories, and writing to.git, so a realistic setup now has to relax at least one ofnetwork_hosts,allow_all_hosts,write_paths,allow_fs_write_allorallow_unsandboxedunderagent.sandbox_permissions. None of that was expressible from.rulesync/permissions.jsonc:zedwas still bound to the genericCanonicalPermissionsOverrideSchema.agent.profileshad the same problem from the other direction. Profiles decide which tools exist in a thread — a separate enforcement stage fromtool_permissions, since a tool absent from the active profile cannot be used no matter what the permission rules say. #2033 looked at profiles as a subagents surface and was closed; the permissions angle was never covered.What changed
A new
ZedPermissionsOverrideSchemainsrc/types/permissions.tscarries the generic tool-scopedpermissionsurface plus two verbatim passthrough blocks, andzedmoves off the generic schema onto it:sandbox_permissions— a barelooseObject, written straight intoagent.sandbox_permissions, mirroring the Kilo / Claude Code / Codex CLIsandboxpassthrough precedent. The keys are documented rather than enumerated, since upstream adds to them release over release.profiles— keyed by profile id, withname/tools/enable_all_context_servers/context_servers/default_modeltyped but loose, like Kimi Code'stools.enabled/disabledblock. No canonicalization is attempted.zed-permissions.tswrites both through the existing shared-config gateway path (thepermissionsfeature already owns the wholeagentkey at all three Zed settings paths) and lifts both back into thezedoverride on import, so a hand-written sandbox policy or profile set round-trips instead of being lost on the next generate.Fail-closed guard
The override cannot reach past its own surface:
buildZedOverridePatchreads the two keys by name rather than spreading the override object, so an unlisted key is inert.agent.tool_permissionsis called out explicitly and ignored with a warning rather than silently, since it is the canonicalpermissionblock's surface end to end — the analogue of Kiro'sread/write/grep/globrejection. A test asserts a canonicaldenysurvives an override that tries to settool_permissions.default = "allow".A key the override supplies replaces the existing block wholesale (Zed reads each as one policy unit, so a deep merge would leave half of a rewritten sandbox policy behind); a key it omits leaves whatever is in
settings.jsonalone rather than deleting it.Tests
zed-permissions.test.tscovers the verbatim write, round-trips in both project and global scope (the global dir is platform-branched), the omitted-override import, wholesale-replace vs. preserve, and thetool_permissionsrejection.src/e2e/e2e-permissions.spec.tsgains an end-to-end generate case. Docs note added to the Zed permissions section ofdocs/reference/file-formats.md, withdocs-contentregenerated.pnpm cicheckgreen;npx vitest run --config vitest.e2e.config.ts src/e2e/e2e-permissions.spec.tsgreen (81 tests).The issue stays open — the remaining Zed gaps are untouched here.
🤖 Generated with Claude Code