Problem
omac sandbox run grants the workdir read+write. For a plain clone this covers .git (it lives inside the workdir), so git operations work. For a linked worktree, git splits repo state across two paths:
- workdir:
…/<repo>/.worktrees/<name>/ ← granted
- git-admin dir:
…/<repo>/.git/worktrees/<name>/ ← NOT granted (sibling, outside the workdir)
When the agent runs git add / git commit, git touches the admin dir (index, HEAD, ORIG_HEAD, logs, objects, refs) and gets EPERM from the sandbox (Seatbelt on macOS, Landlock on Linux). The agent can't commit from any linked worktree.
This affects every harness (opencode, claude, codex) and any host app that materializes agent workspaces as linked worktrees under <repo>/.worktrees/.
Root cause
The sandbox's "workdir = self-contained unit" invariant holds for plain clones but not for linked worktrees: a linked worktree's .git is a file pointing at git rev-parse --git-common-dir, which sits outside the workdir.
Suggested fix
In the workdir-grant codepath of omac sandbox run, after resolving the workdir, detect a linked worktree (.git is a file, not a dir). If so, resolve git rev-parse --git-common-dir and auto-grant the commit-relevant subdirs of the common dir:
--allow <common>/objects # shared object store
--allow <common>/refs # shared refs
--allow <common>/logs # reflogs
--allow <common>/worktrees/<name> # per-worktree index/HEAD/ORIG_HEAD/logs
--read <common>/config # read-only: git reads, agent can't mutate
--read <common>/info
--deny <common>/hooks/* # closes the host-side hook persistence vector
Why this scope
objects/, refs/, logs/, worktrees/<name>/ are what git add/commit actually write. Granting them restores parity with a plain clone (which the sandbox already permits by virtue of .git being inside the workdir).
hooks/* is denied because a writable hooks dir lets a sandboxed agent plant pre-commit/core.hooksPath that runs un-sandboxed, as the host user on the next host-side commit — a clean persistence/exfil primitive that escapes the sandbox boundary entirely.
config is read-only to block core.hooksPath / credential.helper / url.insteadOf mutation by the sandboxed agent.
Cross-worktree note
objects/ and refs/ are shared across all linked worktrees of the same repo, so an agent in worktree A can rewrite refs/objects visible to sibling worktree B. This is inherent to "the agent can commit" — refs/objects are global by design. The scoped grant doesn't widen this beyond the plain-clone baseline; it only restores parity.
Alternatives considered
- Per-launch
--allow via the harness wrapper (e.g. oco): works as a workaround but must be re-implemented in every harness wrapper and leaks the omac-internal worktree geometry into every caller.
Expected behavior
After the fix, git add / git commit succeed inside any linked worktree under omac sandbox run, for any harness, with the same security profile as a plain clone.
Problem
omac sandbox rungrants the workdir read+write. For a plain clone this covers.git(it lives inside the workdir), so git operations work. For a linked worktree, git splits repo state across two paths:…/<repo>/.worktrees/<name>/← granted…/<repo>/.git/worktrees/<name>/← NOT granted (sibling, outside the workdir)When the agent runs
git add/git commit, git touches the admin dir (index, HEAD, ORIG_HEAD, logs, objects, refs) and gets EPERM from the sandbox (Seatbelt on macOS, Landlock on Linux). The agent can't commit from any linked worktree.This affects every harness (opencode, claude, codex) and any host app that materializes agent workspaces as linked worktrees under
<repo>/.worktrees/.Root cause
The sandbox's "workdir = self-contained unit" invariant holds for plain clones but not for linked worktrees: a linked worktree's
.gitis a file pointing atgit rev-parse --git-common-dir, which sits outside the workdir.Suggested fix
In the workdir-grant codepath of
omac sandbox run, after resolving the workdir, detect a linked worktree (.gitis a file, not a dir). If so, resolvegit rev-parse --git-common-dirand auto-grant the commit-relevant subdirs of the common dir:Why this scope
objects/,refs/,logs/,worktrees/<name>/are whatgit add/commitactually write. Granting them restores parity with a plain clone (which the sandbox already permits by virtue of.gitbeing inside the workdir).hooks/*is denied because a writable hooks dir lets a sandboxed agent plantpre-commit/core.hooksPaththat runs un-sandboxed, as the host user on the next host-side commit — a clean persistence/exfil primitive that escapes the sandbox boundary entirely.configis read-only to blockcore.hooksPath/credential.helper/url.insteadOfmutation by the sandboxed agent.Cross-worktree note
objects/andrefs/are shared across all linked worktrees of the same repo, so an agent in worktree A can rewrite refs/objects visible to sibling worktree B. This is inherent to "the agent can commit" — refs/objects are global by design. The scoped grant doesn't widen this beyond the plain-clone baseline; it only restores parity.Alternatives considered
--allowvia the harness wrapper (e.g.oco): works as a workaround but must be re-implemented in every harness wrapper and leaks the omac-internal worktree geometry into every caller.Expected behavior
After the fix,
git add/git commitsucceed inside any linked worktree underomac sandbox run, for any harness, with the same security profile as a plain clone.