Filesystem grants
What an agent may read and write is declared in its profile and installed into a kernel sandbox at startup. Those are not the same thing, and the gap between them is where the confusing failures live โ a grant can be written down, dropped by policy, and never reach the kernel at all.
mur agent perm list-paths mur
agent 'mur' โ sandbox enforcing (macos-sbpl)
READ
โ /Volumes/Firecuda4tb/Projects/mur
โ /Volumes/Firecuda4tb/Projects/cc-proxy
dropped โ path does not exist on disk
โ /Users/david/.mur/skills
Three states, not two
| State | Where it lives | What it means |
|---|---|---|
| granted | profile.yaml | You asked for it |
| admitted | after policy | It survived the checks โ a path that does not exist on disk is dropped |
| enforced | the running sandbox | The kernel actually received it |
list-paths shows all three at once: โ for a grant that reached the kernel, โ dropped with the reason, and a plain ยท for a grant recorded but not yet enforced because the agent is not running.
The header is the fourth fact โ whether the sandbox is enforcing at all, and which backend installed it. An agent whose seal failed is not an agent with no grants; it is a different situation entirely, and the two used to look identical.
Granting
mur agent perm allow-read mur /path/to/tree
mur agent perm allow-write mur /path/to/tree
mur agent perm deny-path mur /path/to/secret
mur agent perm list-hosts mur
Grants are recursive: allowing a directory allows everything under it. Changes take effect on the agent's next start โ the sandbox is installed once, at startup, and cannot be widened afterwards.
allow-write refuses a path that does not exist, so a write grant is always for something real. When a write is denied at run time, the agent's own error names the nearest existing ancestor you could grant instead of the path it tried.
Why a grant gets dropped
The sandbox backends differ in what they can express. Linux Landlock has no deny rule, so an allow that overlaps a protected path has to be dropped whole; macOS SBPL can install the allow and re-close the protected paths after it. A grant that works on one host can therefore be dropped on the other โ which is why the drop is reported per path, with its reason, rather than summarised.
The kernel is not the only gate. MUR's tools check the same grants in-process before acting, and on Linux that check is the only place a deny-within-allow is enforced, precisely because Landlock cannot express one. A path can therefore be refused by the tool while the kernel would have allowed it โ see Troubleshooting for what that looks like.
Two files are always denied to the agent itself, on every backend: its own profile.yaml and its identity.key. An agent cannot read its own configuration or its private key, so anything the agent needs to know about its own grants has to be handed to it, not read back.
That is self-protection, and it is the narrow case. A larger set of paths is refused to every agent โ other agents' directories and signing keys, ~/.mur/secrets, ~/.mur/auth.json, the host identity.key, the runtime binary and the autostart directories. Those are listed with their reasons under Troubleshooting.
Related
- Build Lane โ
allow-spawn-dir, for toolchains that compile and then run their own output.