Quick start
Five steps, on macOS, from nothing to a sandboxed and recorded Claude Code session.
Install both binaries#
Install nd7 and nd7-exec with one cargo command.
cargo install --locked --git https://github.com/nd7-dev/nd7-core
That single command installs both programs into ~/.cargo/bin. They must stay side by side, because nd7 run finds nd7-exec by looking beside itself and refuses to start if it is missing or writable by anyone but you.
Check that it worked#
nd7 --help lists the commands; nd7-exec on its own prints usage.
nd7 --help
nd7-exec
nd7 --help prints record, verify, enroll, ship, run, hook-prefix, allow and deny. nd7-exec prints its own usage and exits 2, which is the expected result outside a session.
Run Claude Code inside the sandbox#
Change into your project and start the session there.
cd your-project
nd7 run claude
The directory you are in is the project: the one place the agent may write from the start. Before Claude Code starts, nd7 run prints one line naming the session:
nd7 run: session 41287 under nd7's policy; a sandbox the program applies itself is refused
Let the agent write somewhere else, mid-session#
From another terminal, grant a path while the session is still running.
nd7 allow ~/data
nd7 deny ~/data
The next Bash command already runs under the new rules — no restart, no signal. Grants reach Bash commands but not the Write and Edit tools, which run inside the claude process.
Turn on the audit log#
Register nd7 record as a hook in ~/.claude/settings.json for every project, or in the project's own .claude/settings.json.
{
"hooks": {
"SessionStart": [{ "hooks": [{ "type": "command", "command": "nd7", "args": ["record"], "timeout": 5 }] }],
"UserPromptSubmit": [{ "hooks": [{ "type": "command", "command": "nd7", "args": ["record"], "timeout": 5 }] }],
"PreToolUse": [{ "hooks": [{ "type": "command", "command": "nd7", "args": ["record"], "timeout": 5 }] }],
"PostToolUse": [{ "hooks": [{ "type": "command", "command": "nd7", "args": ["record"], "timeout": 5 }] }],
"PostToolUseFailure": [{ "hooks": [{ "type": "command", "command": "nd7", "args": ["record"], "timeout": 5 }] }],
"Stop": [{ "hooks": [{ "type": "command", "command": "nd7", "args": ["record"], "timeout": 5 }] }],
"SessionEnd": [{ "hooks": [{ "type": "command", "command": "nd7", "args": ["record"], "timeout": 1 }] }]
}
}
nd7 run sets up the sandbox but does not register the recorder, so this is a separate, one-time step. Afterwards, check a session's hash chain:
ls ~/.local/state/nd7/sessions/
nd7 verify <session-id>
Each directory under ~/.local/state/nd7/sessions/ is one session, named after Claude Code's own session id; that name is the <session-id> argument.
Next#
- A session, start to finish: the same session in detail, including what
nd7 runpasses to Claude Code and what happens at the first denial. - How the macOS sandbox works: the exact rules, rule by rule.
- Change the rules while the agent works: what
nd7 allowandnd7 denydo, and when. - How the audit log works: what ends up on disk, and what
nd7 verifyproves.