This is the recommended way to run SafePilot for most users because it:
- makes dependencies predictable
- lets you run with a read-only root filesystem
- keeps secrets in files (Docker secrets or bind-mounted
600files)
The CLI binary name is safepilot (used in commands below).
See also:
- Security docs index:
docs/security/README.md - Vulnerability reporting:
SECURITY.md
- Create secret files (permissions matter):
mkdir -p secrets
chmod 700 secrets
printf '%s' '123456:abc' > secrets/bot_token
printf '%s' 'sk-...' > secrets/openai_key
printf '%s' 'enc-or-raw-master-key' > secrets/master_key
chmod 600 secrets/*Alternative: generate file-based secrets from .env automatically:
You can either do Step 1 manually, or use one of the scripts below.
./scripts/sync-secrets-from-env.sh
docker compose -f docker-compose.yml -f docker-compose.secrets.generated.yml up -dWindows PowerShell variant:
powershell -ExecutionPolicy Bypass -File .\scripts\sync-secrets-from-env.ps1
docker compose -f docker-compose.yml -f docker-compose.secrets.generated.yml up -dWhat this does:
- Parses
.envsafely (without executing it) - Writes known secret values to
./secrets/*with strict file permissions - Generates
docker-compose.secrets.generated.ymlwith extra*_FILEwiring for integrations
Optional (recommended): set your own master key file.
SafePilot enables encryption at rest by default. If you set ORCH_MASTER_KEY_FILE, you control
the key source explicitly (recommended in production) and SafePilot can
decrypt enc:v1:... values when loading secrets from *_FILE paths. That allows you to store
encrypted secrets on disk.
Example:
# Generate a master key (32 bytes, base64) and store it with strict perms.
openssl rand -base64 32 > secrets/master_key
chmod 600 secrets/master_key
# Encrypt and store your OpenAI key.
printf '%s' 'sk-...' | docker run --rm -i \
-e ORCH_MASTER_KEY_FILE=/run/secrets/master_key \
-v "$PWD/secrets/master_key:/run/secrets/master_key:ro" \
ghcr.io/3dcf-labs/safepilot:latest \
safepilot encrypt > secrets/openai_key
chmod 600 secrets/openai_key- Edit
docker-compose.yml:
- set
ALLOWED_USER_ID - set
DEFAULT_REPOif you want repo-oriented tasks (git clone / repo reads / code changes) - choose your provider (
OPENAI_API_KEY_FILE/ANTHROPIC_API_KEY_FILE)
- Start it:
docker compose up -d
docker compose logs -f- The container is the main isolation boundary in this setup.
- The compose example sets
TG_ORCH_DANGEROUS_SANDBOX=offto disable bubblewrap inside the container. - If you run on Linux and want bubblewrap anyway, set:
TG_ORCH_DANGEROUS_SANDBOX=auto(orbwrap)- optionally
TG_ORCH_DANGEROUS_SANDBOX_NET=onto pass--unshare-netforshell/validate.
If you enable LLM_MODE=agent, keep these defaults unless you understand the risk tradeoffs:
AGENT_ENABLE_WRITE_TOOLS=0AGENT_ENABLE_BROWSER_TOOL=0
The bot requires explicit /approve, /trusted, and /unsafe checkpoints before higher-risk work
will run.
See also: