Home
Why Sandlock
How It Works Use Cases Comparison Security Model
Docs
Documentation Home Getting Started CLI Reference Python SDK Sandbox Reference FAQ
Products
Overview Sandbox HTTP API Sandbox Scheduler
GitHub Schedule a Demo
Sandlock / Docs /Getting Started

Getting Started

Check the kernel, install from the package index, run something confined. If your host is on Linux 6.12 or later this takes about five minutes, most of which is Cargo compiling the CLI.

Updated

Requirements

Sandlock enforces its full protection set on Linux 6.12 or later, which is where Landlock ABI v6 lands. That is the default strict posture, not a hard floor: on older kernels, individual protections can be waived per policy. The CLI installs through Cargo and needs Rust 1.70 or later. The Python SDK needs Python 3.8 or later and is optional.

You do not need root, cgroups, user namespaces, a container runtime, or KVM.

Feature Minimum kernel
seccomp user notification5.6
Landlock filesystem rules5.13
Landlock TCP port rules (ABI v4)6.7
Landlock IPC scoping (ABI v6)6.12

Running on a kernel below 6.12 is possible, but each missing protection has to be waived explicitly per policy. See Kernel Protections.

Running inside Docker

Sandlock runs inside a Docker container, with one caveat: the supervisor duplicates the child's file descriptors with pidfd_getfd, and Docker's default seccomp profile only permits that syscall when the container holds CAP_SYS_PTRACE. Without it, every sandlock run fails at startup with pidfd_getfd: Operation not permitted, even though sandlock check reports full support.

Grant the capability the supervisor needs
$ docker run --cap-add SYS_PTRACE <image> sandlock run ...

This is a gate in the seccomp profile, not a kernel restriction, so there is no need for seccomp=unconfined or a privileged container. --no-supervisor mode never calls pidfd_getfd and runs under the default profile as is.

Install

CLI

The crate is named sandlock-cli; the binary it installs is sandlock.

Install the sandlock binary from crates.io
$ cargo install sandlock-cli

Python SDK

Install the Python SDK from PyPI
$ pip install sandlock

# with the MCP server extra
$ pip install 'sandlock[mcp]'

From source

Building from source is only needed for development or for changes that have not shipped in a release. The Python package builds the Rust FFI library as part of its install, so a Rust toolchain has to be present.

Build the binary, the CLI, and the Python SDK from a checkout
$ git clone https://github.com/multikernel/sandlock.git
$ cd sandlock
$ cargo build --release

# CLI only
$ cargo install --path crates/sandlock-cli

# Python SDK, with the MCP server extra
$ cd python
$ pip install -e '.[mcp]'

Verify the host

sandlock check reports the running kernel's Landlock ABI and which protections are available. Run it before deploying to a new fleet, not after.

Confirm kernel support
$ sandlock check

Your first sandbox

Sandlock is default-deny. A sandbox with no filesystem rules cannot read /usr, which means it cannot load a dynamic linker, which means nothing runs. Every real invocation names the paths it needs.

Basic confinement
# -r grants read, -w grants read and write
$ sandlock run -r /usr -r /lib -w /tmp -- ls /tmp

# An interactive shell needs a few more paths
$ sandlock run -i \
    -r /usr -r /lib -r /lib64 -r /bin -r /etc -w /tmp \
    -- /bin/sh

Grants are recursive. -r /usr covers everything beneath /usr, because Landlock rules are PATH_BENEATH grants. You do not need to enumerate subdirectories, and listing both a directory and something inside it is redundant.

Add an envelope

Filesystem rules say what the workload can reach. The other three dimensions say how much of the machine it can consume, where it can talk, and how long it may run.

Resources, time, and one network destination
# 512 MB of memory, 20 concurrent processes, 30 second timeout
$ sandlock run -m 512M -P 20 -t 30 -- ./compute.sh

# Exactly one host on exactly one port; everything else is denied
$ sandlock run --net-allow api.openai.com:443 \
    -r /usr -r /lib -r /etc -- python3 agent.py

# Start from a minimal environment and set what you need
$ sandlock run --clean-env --env CC=gcc \
    -r /usr -r /lib -w /tmp -- make

Protect the working directory

Setting --workdir puts a copy-on-write layer over that directory. Writes are staged rather than applied, then committed when the command exits successfully and discarded when it fails. --dry-run takes it one step further: it runs the command, reports what would have changed, and then discards everything.

See what a command would do before it does it
$ sandlock run --dry-run --workdir . \
    -w . -r /usr -r /lib -r /bin -r /etc -- make build
A  build/out.o
M  Cargo.lock
D  build/stale.o

From Python

The Python SDK takes the same policy as a dataclass. Field names match the CLI concepts, and the sandbox object carries no runtime state, so it can be built once and reused.

python
from sandlock import Sandbox

sandbox = Sandbox(
    fs_writable=["/tmp/sandbox"],
    fs_readable=["/usr", "/lib", "/etc"],
    max_memory="256M",
    max_processes=10,
    clean_env=True,
)

result = sandbox.run(["python3", "-c", "print('hello')"], timeout=30)
assert result.success
assert b"hello" in result.stdout

Save the policy

Once a policy stops changing, move it into a TOML profile in ~/.config/sandlock/profiles/ and reference it by name. Profiles use a sectioned schema; flat top-level keys are rejected rather than silently ignored.

~/.config/sandlock/profiles/build.toml
[program]
exec = "make"
args = ["-j4"]
clean_env = true
env = { CC = "gcc", LANG = "C.UTF-8" }

[filesystem]
read  = ["/usr", "/lib", "/lib64", "/bin", "/etc"]
write = ["/tmp/work"]

[limits]
memory    = "512M"
processes = 50
Use it
$ sandlock profile list
$ sandlock run -p build              # uses [program].exec and args
$ sandlock run -p build -- make test # trailing command wins

You do not have to write the profile by hand. sandlock learn runs a workload under observation and emits a profile covering the paths, connections, and resource peaks it actually used. See Profiles and learn.

Run the tests

Rust and Python test suites
$ cargo test --release

$ cd python && pip install -e . && pytest tests/

Tests that spawn real sandboxes are heavier than they look, since each one is a full sandlock process with its own supervisor. Running too many concurrently exhausts kernel limits and causes hangs, so cap the parallelism with --test-threads=4.

Where to go next