Skip to content

Configure the sandbox

reyn's sandbox layer isolates subprocess execution at the operator level. The operator sets the backend and policy in reyn.yaml; workflows do not control their own containment. Sandbox is orthogonal to permissions — see Sandbox and permissions.

Choose a backend

# reyn.yaml
sandbox:
  backend: auto          # auto | seatbelt | landlock | noop
  on_unsupported: warn   # warn | error | ignore

backend: auto (the default) picks the best available backend for the current platform:

Platform Condition Backend
macOS sandbox-exec available Seatbelt (SBPL deny-default)
Linux kernel ≥ 5.13, sandbox-linux package installed Landlock (+ optional seccomp-BPF)
Other Noop (audit-only, no enforcement)

on_unsupported controls what happens when you force a backend that is unavailable:

Value Behaviour
warn (default) Log a warning and fall back to Noop
error Raise an error — use this when enforcement is a hard requirement
ignore Silently fall back to Noop

Set the agent-level sandbox policy

sandbox.policy lets the operator declare a deterministic, operator-controlled sandbox policy. When set, it applies to all sandboxed_exec ops and to the SandboxLayer of the permission intersection — a workflow or the LLM cannot widen it.

sandbox:
  backend: auto
  policy:
    network: false
    write_paths:
      - "{{workspace}}/output"
    read_deny_paths:
      - "~/.ssh"
      - "~/.aws"
    timeout_seconds: 120

When sandbox.policy is absent (the default), there is no agent-level restriction: op-level fields govern, and the SandboxLayer is unrestricted.

Policy fields

Field Type Default Meaning
network bool false Allow outbound network. The primary exfiltration gate.
write_paths list of paths [] Paths the process may write (tight guard). Write implies read.
read_deny_paths list of paths [] Sensitive paths to deny from the broad read surface (defense-in-depth). Enforced only on backends that support deny-after-allow (Seatbelt); not enforceable on Landlock.
read_paths list of paths [] Legacy — formerly the strict read allowlist. Reads are broad by default; this field now documents intended read targets only.
allow_subprocess bool false Allow child-process spawning. Enforced on Linux (seccomp) and macOS (Seatbelt).
env_passthrough list of strings [] Env vars passed through to the process. PATH is always passed.
timeout_seconds int 60 Wall-clock limit; process is killed on expiry.

Scoping model

reyn uses a broad-read, tight-write, network-gated model:

  • Reads are broad. The process can read most of the filesystem. System-path enumeration for dylib loading works without enumeration in policy.
  • Network is the exfiltration gate. With network: false (the default), the process can read broadly but cannot send data out.
  • Writes are tight. Only paths in write_paths are writable.
  • read_deny_paths is defense-in-depth. Carves out sensitive locations from the broad read surface where the backend can express a deny-after-allow rule.

Per-backend behavior

Seatbelt (macOS)

Uses sandbox-exec with an SBPL deny-default profile. Strongest containment on macOS.

Field Enforcement
write_paths Enforced
network Enforced
read_deny_paths Enforced — SBPL deny-after-allow
allow_subprocess Enforced — denies process-fork when off; the target's own exec still works via process-exec*
timeout_seconds Enforced

Landlock (Linux)

Uses the Linux Landlock LSM with path-beneath allowlist rules.

Field Enforcement
write_paths Enforced — path-beneath write rules
network Enforced on Linux 6.7+ (ABI v4); warning logged on older kernels
read_deny_paths Not enforced — Landlock is allowlist-only and cannot carve a subpath out of an allowed parent. The network gate is the primary exfiltration control.
allow_subprocess Enforced via seccomp-BPF when available
timeout_seconds Enforced

Noop

No containment enforced. Policy fields are recorded in the audit log but have no effect. Use only in trusted environments where enforcement is unavailable.

Run in a container (mount mode)

For the strongest isolation — or to run workflows against a consistent Linux environment regardless of the host OS — use the Docker backend:

# Launch a new container (mount mode)
reyn run my_skill --env-backend=docker

# Use a specific image
reyn run my_skill --env-backend=docker --image my-registry/my-image:latest

# Add extra bind mounts
reyn run my_skill --env-backend=docker \
  --mount /data/inputs:/data/inputs:ro \
  --mount /data/outputs:/data/outputs:rw

# Keep the container after the run (for inspection)
reyn run my_skill --env-backend=docker --keep-container

# Attach to an already-running container
reyn run my_skill --env-backend=docker --container my-container --repo-dir /workspace

In mount mode, the workspace root is automatically bind-mounted at /workspace inside the container. The sandbox backend used inside the container is determined by reyn.yaml sandbox.backend as usual (typically landlock on Linux).

Default image

When --image is omitted, reyn uses a bundled base image built for the current platform. To use a custom image, pass --image or set the default in reyn.yaml (see reyn.yaml reference).

devcontainer.json

If the workspace ships a devcontainer.json (.devcontainer/devcontainer.json or .devcontainer.json), reyn reads a minimal subset to seed the launch: image, postCreateCommand, mounts, and remoteUser. An explicit --image always overrides the devcontainer.

  • Image-based (image: ...) — launched directly.
  • Build-based (dockerFile / build) — reyn builds the Dockerfile on demand (docker build) and launches the result. The built image is tagged by content hash, so it is rebuilt only when the Dockerfile / build args / target change. build.args and build.context are honored.
  • Compose-based (dockerComposeFile) — not supported (the launcher is single-container); reyn warns and falls back to the default image.

Build runs the workspace Dockerfile on your host

Building a build-based devcontainer runs that Dockerfile's RUN steps on your host Docker daemon at build time — these are not confined by reyn's runtime sandbox (the network-off / non-root / read-only-rootfs flags apply to the running container, not to docker build). This is the same trust model as VS Code's "Reopen in Container": only use build-based devcontainers from workspaces you trust. reyn logs the build for visibility; --env-backend=docker is the opt-in.

See also