# Sandbox
The sandbox restricts the process to a configurable set of
filesystem paths using Linux Landlock. It's opt-in, works in every
host (`deft`, `retro`, `retra`), and is enforced by the kernel — a
stray `[fs/write]` or file open outside the granted paths simply
fails, instead of silently succeeding.
Networking is not restricted. Landlock is filesystem-only; the
process keeps full network access.
## Enabling
Set `DEFT_SANDBOX=1` (or `true`) in the environment:
```bash
$ DEFT_SANDBOX=1 deft script.dft
$ DEFT_SANDBOX=1 retro
````
Without the variable the sandbox is a no-op. It is also a no-op on
non-Linux platforms and on kernels too old for Landlock (kernel 5.13+,
see Kernel Support); those cases print a message
and continue unsandboxed rather than refusing to start.
The sandbox is applied after the prelude and config registry are
loaded but before user code runs and before the TUI event loop
starts, so all initialisation reads complete first. Application is a
one-way door (`landlock_restrict_self`): the process can never widen
its own access afterwards.
## Configuration
The static path lists live in the project prelude under the
`:sandbox` key (see Prelude):
%Prelude{
:sandbox %{
:readonly @{ "/etc" "/usr/bin" "/usr/lib" "/usr/lib64" "/usr/share" "/proc" "/sys" }
:writable @{ "~/.config" "~/.local" }
}
}
- `:readonly` — paths readable (and executable) but not writable.
- `:writable` — paths fully writable: read, write, create, remove.
Both lists are optional. A leading `~` is expanded to `$HOME` when
the sandbox is applied, so `"~/.config"` grants the subtree beneath
the real home directory.
`deft init` writes a template `:sandbox` block for you. Edit the
lists directly in `.deft/prelude.dft`, or use the `deft sandbox` CLI
which edits them for you:
```
$ deft sandbox list # show both lists
$ deft sandbox add /srv/data # add read-only
$ deft sandbox add ~/code/write-dir -w # add writable
$ deft sandbox remove /srv/data
````
See [The `deft` Binary](../08-Tooling/cli) for the full subcommand
reference.
## What Is Always Granted
A small set of host-essential, environment-derived grants is applied
by the runtime itself and cannot be edited away:
| Path | Access | Why |
|------|--------|-----|
| cwd subtree | full | the project the runtime runs in |
| `/tmp` | full | temp files, sockets |
| `$XDG_RUNTIME_DIR` | rw socket | Wayland/X11 compositor socket |
| `$HOME` | read-only | Xauthority, fontconfig cache, config reads |
| `/dev`, `/dev/pts` | rw + ioctl | GPU render nodes, input, integrated-terminal PTYs |
| `/` | execute-only | absolute-path resolution of binaries |
| font path (TUI) | read-only | when the configured font lives outside cwd + `/tmp` |
Writable sub-trees like `~/.config` from the `:writable` list union
over the read-only `$HOME` rule within the same ruleset, so they
become writable without widening the rest of the home directory.
## Semantics and Limits
- Directory-granular grants. A rule roots on a directory and
covers its subtree. Adding a list entry that names a file is
warned about and skipped — add the parent directory instead.
- One-way door. After startup the process's filesystem view is
fixed for its lifetime. There is no runtime escape hatch.
- Filesystem only. Sockets, network, and process signals are
unaffected. This is not a full security sandbox — for untrusted
code, pair it with `runtime/*` heap isolation (see
Runtimes); child runtimes share the process and
therefore the same sandbox.
- Not a per-app boundary. The sandbox bounds the whole process.
All panels in a TUI host and all child runtimes run inside the one
set of grants.
## Kernel Support
Landlock ABIs are detected automatically and the widest supported
set of access rights is used:
| ABI | Kernel | Notes |
|-----|--------|-------|
| v6 | 6.13+ | scoped access |
| v4 | 6.7+ | networking field in the ruleset attr |
| v3 | 6.2+ | up to `TRUNCATE` |
| v2 | 5.19+ | up to `REFER` |
| v1 | 5.13+ | baseline: read/write/create/remove/exec |
On kernels without Landlock the process prints
`sandbox: landlock unavailable (kernel too old)` and continues
without restriction.
## Diagnosing
Denied operations fail with the usual OS-level errors (`permission`
denied`, `no such file or directory` on open), which surface as`
normal Deft errors from `fs/*` and `sqlite/*` stdlib functions. Check the
startup line `sandbox: active (landlock, cwd + /tmp + prelude paths)`
to confirm the sandbox engaged, then add the missing path to the
appropriate list:
```
$ deft sandbox list
read-only:
/etc
/usr/bin
writable:
~/.config
$ deft sandbox add ~/data -w
added ~/data (writable)
````
## See Also
- Prelude — the `:sandbox` key lives in `.deft/prelude.dft`
- [The `deft` Binary](../08-Tooling/cli) — `deft sandbox` subcommand
- Runtimes — heap isolation vs. OS sandboxing