What happens when a command is denied
Under nd7 a command that steps outside the session's rules does not prompt anyone: it fails. This page explains the three places a refusal can come from — the kernel, nd7-exec, and the model's own report — how to tell them apart, and what to do about each. Telling them apart matters, because only one of the three is fixed by nd7 allow.
What the kernel does#
Nothing is intercepted, queued or asked about. When a confined process makes an operation the profile denies, the kernel fails that operation with EPERM, the error code errno(3) describes as "Operation not permitted". The program sees an ordinary permission error, so what reaches the terminal is whatever that program prints for one:
zsh: /Users/you/notes.txt: Operation not permitted
The command's own exit status follows from the failure — a shell redirection that cannot open its target exits 1, for example. There is no nd7 marker on the line, because nd7 is not in the path of that write at all. The kernel is.
This is the common case, and the one nd7 allow fixes when it is a write outside the project.
What nd7-exec reports#
Every Bash command runs through nd7-exec, which applies the session's current rules to itself and then becomes the shell. If it cannot do that, it runs nothing at all and says so, with its own name first so you can tell it apart from the shell and from Claude Code:
nd7-exec: no nd7 session in this process's ancestry
It exits 126 in every such case. The reasons, from src/bin/nd7-exec.rs:
no nd7 session in this process's ancestry: nothing in the process's parent chain owns a session directory under~/.nd7/sessions. The command was not started inside annd7 runsession has no policy.sb: the session directory exists but holds no profileread <path>: <error>: the profile could not be readapply session policy: <error>: the kernel refused the profileexec /bin/zsh: <error>: the shell could not be started
A usage error — anything other than exactly -c <command> — prints the nd7-exec usage and exits 2.
These are not permission decisions about your command; they mean the command never ran. nd7 allow will not help. Either the command was run outside a session, or the session's own state is wrong.
What the model is told#
Two things, both installed by nd7 run claude.
A paragraph appended to the system prompt. It is there so the model reads a failure as nd7's rules rather than as Claude Code's permission prompts, and so it reports the denial to you instead of trying to work around it:
This session runs under nd7's kernel sandbox. Bash commands are routed through nd7-exec by a hook and run under the session's policy: the project directory is writable, most of the rest of the filesystem is not, and only HTTPS egress is open. An 'operation not permitted' error is that policy, not Claude Code's permission rules. Do not try to route around it; tell the user what was denied.
nd7 allow <path>widens the policy for Bash commands from the next call on; the Write, Edit and Read tools see only the fixed policy, so for those the user must restart under a wider one.
A reason on every Bash call. The PreToolUse hook in src/hook_prefix.rs answers each Bash call with permissionDecision: allow and
nd7: the command runs under this session's sandbox policy
The allow is not nd7 waving the command through: it says that the permission dialog is not the thing deciding here. The profile nd7-exec applies is. Claude Code does the same for commands its own sandbox has confined; once the kernel is the boundary, a second prompt only asks a person to decide again what the rules have already settled.
So in practice what you see in the transcript is the agent running a command, the command failing with Operation not permitted, and the agent telling you which path or which host it wanted.
How to respond#
A write outside the project. Grant it from another terminal and let the agent try again:
nd7 allow ~/data
The next Bash command has it. See Change the rules while the agent works.
A write the Write or Edit tool wanted. Those run inside the claude process, which the kernel confined when the session started and which cannot be re-confined while it runs. A grant will not reach them. Restart the session under a wider project, for example nd7 run claude --resume <id>.
A read of ~/.ssh, ~/.aws or ~/.nd7. These are denied outright and there is no grant for reads. If the agent genuinely needs a credential, give it to the agent another way; if it needs SSH, note that git over SSH does not work under the sandbox while git over HTTPS does.
A network connection that is not HTTPS. The rules allow DNS and TCP port 443, and nothing else. There is no command to widen that: nd7 allow takes a path. Anything on another port — SSH, a database connection, a local development server on port 3000 — fails inside the sandbox, and the only way round it today is to run that part outside the session.
ps or pgrep. Denied, as recorded in the README's known limits.
nd7-exec: … with exit 126. The command never ran. Check that you are inside an nd7 run session; if you are, that the session directory under ~/.nd7/sessions/<pid> still holds policy.sb.
What a denial is not#
It is not a prompt you can answer in the terminal, and there is no bypass flag. It is also not recorded anywhere by the sandbox: nd7's audit log is written by Claude Code's hooks, so a denial appears in it the way the agent saw it — a failed tool result — and not as a decision by the sandbox. Recording what the kernel itself observed is a planned phase, not something that exists today. See How the audit log works.