Sandbox¶
Reyn's sandbox layer translates the policy a skill declares into kernel-level enforcement — without any OS code knowing which skill is running. This is a direct application of P3 (OS is the runtime engine) and P7 (OS code must not contain skill-specific strings): the skill declares what it needs; the OS selects how to enforce it.
The sandbox complements the permission model: permissions enforce declared scope at dispatch time (before the op runs); the sandbox enforces the same boundaries at the system-call level while the subprocess is running. The two layers are independent and additive.
SandboxPolicy field reference¶
Defined in src/reyn/sandbox/policy.py. Passed as fields on a sandboxed_exec Control IR op.
| Field | Type | Default | Meaning |
|---|---|---|---|
network |
bool |
false |
Allow outbound network connections |
read_paths |
list[str] |
[] |
Filesystem paths the subprocess may read (glob patterns and {{workspace}} template OK) |
write_paths |
list[str] |
[] |
Filesystem paths the subprocess may write |
allow_subprocess |
bool |
false |
Allow the subprocess to spawn child processes |
env_passthrough |
list[str] |
[] |
Environment variable names passed through to the subprocess (all others are stripped) |
timeout_seconds |
int |
60 |
Wall-clock limit; process is killed on expiry |
Backend selection table¶
get_default_backend(config) selects a backend at runtime based on platform and installed extras. The sandbox.backend config key in reyn.yaml overrides automatic selection.
| Platform | Condition | Backend | Notes |
|---|---|---|---|
| macOS | < 26 | SeatbeltBackend |
SBPL profile via sandbox-exec. Deprecated upstream — Apple removing in macOS 26. |
| macOS | ≥ 26 (future) | AppleContainerBackend |
Not yet implemented (Component E, deferred). Falls back to NoopBackend. |
| Linux | kernel ≥ 5.13, sandbox-linux extra installed |
LandlockBackend + seccomp-BPF |
pip install reyn[sandbox-linux] required. ABI v4+ adds network port rules. |
| Linux | kernel < 5.13 or sandbox-linux not installed |
NoopBackend |
Audit-only; no enforcement. |
| Other | any | NoopBackend |
Audit-only; no enforcement. |
When NoopBackend is used, Reyn logs a one-line WARN on first invocation. Set sandbox.on_unsupported: error to hard-fail instead.
macOS 26.3+ and SeatbeltBackend: sandbox-exec remains shipped in macOS 26.3. An SBPL profile that includes (import "bsd.sb") and (allow process-exec*) is sufficient for the backend to function. See the FP-0017 post-dogfood fix landing notes (commit b477508) for details.
reyn.yaml configuration¶
sandbox:
backend: auto # auto | seatbelt | landlock | noop
on_unsupported: warn # warn | error | ignore
backend: auto— let Reyn pick the best available backend for the current platform (recommended).backend: noop— explicitly opt out of enforcement (useful in CI environments where you audit via events but do not need enforcement).on_unsupported: error— fail skill dispatch if the configured backend is unavailable. Use in production environments where enforcement is a hard requirement.
Declaring a sandbox policy in a skill¶
In a skill's skill.md, add a sandbox: block to any phase that runs sandboxed_exec:
# skill.md excerpt
phases:
- name: run_script
instructions: |
Run the analysis script.
sandbox:
read_paths:
- "{{workspace}}/input"
write_paths:
- "{{workspace}}/output"
network: false
timeout_seconds: 120
The {{workspace}} template is expanded by the OS at runtime to the skill's workspace directory. Skill authors MUST NOT hardcode absolute paths — use {{workspace}} for all workspace-relative paths and /usr/bin, /usr/lib, etc. for system paths (those are automatically allowed on backends that need them for dylib loading).
See also¶
- FP-0017 — design rationale, component history, and backend implementation details.
- Control IR:
sandboxed_exec— op schema and field reference. - Permission model — dispatch-time declared-scope enforcement that the sandbox complements at runtime.