← ScopeShelf

Terminal, iTerm and the sandboxed shell

Help · updated September 12, 2026 · Auf Deutsch lesen

Terminal apps are the one case where ScopeShelf does not sandbox the app. It sandboxes the shell inside it. This page explains why, walks through every setting, and lists the error messages you can run into and what they mean.

On this page
  1. Why a terminal cannot run inside the sandbox
  2. What ScopeShelf does instead
  3. Setting up a terminal launcher in the app
  4. The Shell section, setting by setting
  5. Starting the sandboxed shell
  6. What you can and cannot do inside
  7. Doing it from the command line
  8. What the sandbox enforces, and what it does not
  9. Error messages and what to do

1. Why a terminal cannot run inside the sandbox

Terminal.app, iTerm2, Alacritty, kitty and friends do not start your shell directly. They go through /usr/bin/login, a small program that is marked setuid. macOS refuses to run setuid programs inside a Seatbelt sandbox, whatever the profile says. You can see it yourself:

$ sandbox-exec -p '(version 1)(allow default)' /usr/bin/login -fpl $USER /bin/echo hi
sandbox-exec: execvp() of '/usr/bin/login' failed: Operation not permitted

So a terminal started inside the sandbox opens its window, tries to start a session, and fails. It looks like the app is broken. Nothing you configure in ScopeShelf can change that; it is a rule of the operating system.

ScopeShelf recognises these apps when you pick them. The card says Terminal — the sandbox applies to the shell you start here, the Start button becomes Start shell, and there is no Quit or "Restart protected" for them: quitting your terminal would take every open shell with it, for a start that cannot work.

2. What ScopeShelf does instead

Your terminal runs normally, unsandboxed. Inside it, ScopeShelf starts a sandboxed shell: a zsh (or whatever shell you use) wrapped in the launcher's Seatbelt profile. Everything you start from that shell inherits the sandbox: Claude Code, Codex, npm, build scripts, git. The shell sees your project folder and the folders you granted, and nothing else in your home directory.

The rules are the same three zones as for any launcher:

Everything outside your home directory (/usr, /opt/homebrew, /Applications, /tmp) stays reachable, as it is for every ScopeShelf launcher.

3. Setting up a terminal launcher in the app

  1. New launcher. Under step 1 click Terminal or iTerm in the row Or pick an installed app. You do not need the file dialog. If you prefer it: Terminal.app lives in /System/Applications/Utilities/, and the dialog shows hidden folders, so you can navigate there or press Cmd+Shift+G and paste the path.
  2. Name. The short name derived from it is what you type on the command line later (scopeshelf shell my-name).
  3. Grants. The Terminal and iTerm presets grant nothing by default. The project folder is asked for when you first press Start shell (see below), so you do not have to add it here. Add here what the tools inside need beyond the project. Typical for Claude Code with the native installer:
    # Writable
    ~/.claude                     # settings, sessions
    ~/.local/share/claude         # the binaries
    # Files (granted as single files)
    ~/.claude.json
    ~/.gitconfig
    Reference material you only want the AI to read: add it as read-only.
  4. Shell section (step 4). This is where the shell itself is configured. All lists are measured on your Mac, not guessed. Details in the next section.
  5. Save.

4. The Shell section, setting by setting

You find it under Edit launcher → step 4, Shell. The same settings exist once more under Settings → Shell as the default for every launcher; a launcher only overrides what you set in it.

SettingWhat it does
ProgramWhich shell runs. Default is your login shell ($SHELL). The list comes from /etc/shells. ScopeShelf knows zsh, bash, fish, nushell, ksh, sh, tcsh, elvish, xonsh and PowerShell (pwsh). Other shells start too, but ScopeShelf does not know their startup files.
Login shellStarts the shell with -l, so it reads its profile files (.zprofile) like a fresh terminal window does. On by default.
Working folderThe shell's workspace: it starts here and may write here, even if the folder is not in the grants above. Leave it empty and the app asks for a folder the first time you press Start shell, then remembers it. From the command line, an empty working folder means "start where I ran the command" (see section 7). The home directory itself is refused as a working folder because a sandbox that can write your whole home protects nothing.
Startup filesThe startup files of the chosen shell that actually exist on your Mac (~/.zshenv, ~/.zprofile, ~/.zshrc for zsh). Tick the ones the shell may read. Without them you get a bare shell: no prompt theme, no aliases, no PATH additions.
Files loaded by those startup filesScopeShelf reads the ticked startup files and lists what they source themselves, for example ~/.cargo/env or ~/.nvm/nvm.sh. Tick them too, otherwise the shell prints operation not permitted for that line at every start.
Program foldersFolders from your $PATH that live inside your home directory: ~/.local/bin, ~/.bun/bin, ~/.cargo/bin, nvm's node folders and so on. Everything under home is invisible in the sandbox unless granted, so a tool installed there disappears without its tick. A bin folder brings its lib, libexec and share neighbours along, otherwise npm finds node but not its modules.
Own configuration and history in the sandboxThe shell gets its own configuration directory (ZDOTDIR for zsh, XDG_CONFIG_HOME for fish and nushell) under ~/Library/Application Support/ScopeShelf/shells/<short name>. ScopeShelf writes small bridge files there that load your real startup files, and the shell's history lands there too. Your own ~/.zsh_history is never touched by a sandboxed session. Shells without a movable configuration directory (bash, sh) run without their own history.

5. Starting the sandboxed shell

From the app

Press Start shell on the launcher card, in the detail view, or in the menu bar menu. Two things happen:

  1. Working folder dialog (first time only, when no working folder is set): pick the project folder the shell should work in. ScopeShelf stores it in the launcher. It refuses your home directory and blocked folders such as ~/.ssh.
  2. Your terminal comes to the front with a new window. ScopeShelf types the shell command into it. iTerm and Terminal.app are driven directly; any other terminal gets a window in Terminal.app.

The first time, macOS asks whether ScopeShelf may control your terminal (System Settings → Privacy & Security → Automation). Allow it, otherwise nothing opens.

A Dock starter (created in the detail view) does the same, including the folder dialog.

What the banner tells you

The command line tool currently prints its messages in German. This is what the lines mean:

Gesandboxte Shell (tttt, zsh) — beenden mit `exit`, Details mit `scopeshelf scope`.
Schreibbar: ~/repos/my-project  ~/.claude  ~/.local/share/claude
Nur lesbar: ~/.zshenv  ~/.zshrc  ~/.local/bin
Arbeitsordner ~/repos/my-project ist fuer diese Shell schreibbar freigegeben (zusaetzlich zum Profil).

After the banner you are in your normal prompt, in the working folder. Start Claude Code, Codex or whatever you like. exit ends the sandboxed shell and returns you to the unsandboxed shell of that window.

6. What you can and cannot do inside

7. Doing it from the command line

Install the command once under Settings → Command line tool. It links the scopeshelf binary that ships inside the app into ~/.local/bin (or /usr/local/bin if that folder is yours). Then, in any terminal window:

scopeshelf shell my-name                       # shell in the launcher's profile, in this window
scopeshelf shell my-name --cd ~/repos/other    # another project, just for this start
scopeshelf shell my-name --shell /bin/bash     # another shell, just for this start
scopeshelf shell my-name --no-network          # block outbound network for this start
scopeshelf shell my-name -e FOO=bar            # set an environment variable
scopeshelf shell --app /Applications/iTerm.app ~/repos/x ~/docs:ro
                                               # ad hoc, without a saved launcher: x writable, docs read-only
scopeshelf dry my-name                         # show the profile without starting anything
scopeshelf scope                               # inside a sandboxed shell: what applies here?

Rules for the starting folder on the command line:

For a project shared with a team, put a .scopeshelf file into the repository and run plain scopeshelf shell in that folder:

{
  "launcher": "my-name",
  "shell": { "workingDirectory": "." }
}

Project settings in that file are layered over the launcher's own; a relative working folder is resolved against the project.

8. What the sandbox enforces, and what it does not

Every claim below is tested by a script in the repository (Scripts/check-sandbox-escapes.sh) that actually tries each escape from inside a sandboxed shell, 21 attempts as of 1.1.2; the full table of what is enforced where is in docs/sandbox-enforcement-map.md. Rules marked profile are part of every ScopeShelf sandbox and cannot be switched off from inside.

Enforced by the profile or the kernel

Enforced by macOS, not by the profile

Not protected at all

9. Error messages and what to do

You seeMeaning and fix
/Users/you/.zshenv:.:1: operation not permitted: /Users/you/.cargo/envA startup file loads another file that is not granted. Edit launcher → step 4, Shell → tick it under Files loaded by those startup files. The banner names the file before the shell complains.
… kann kein Arbeitsordner sein: eine Freigabe auf den Benutzerordner (oder darueber) wuerde nichts mehr sperren"Cannot be a working folder": you picked ~ or a parent of it. Pick a project folder.
… liegt im gesperrten Pfad …"Lies in a blocked path": the working folder is under ~/.ssh, ~/.aws or another blocked folder. Blocks always win over grants.
… ist im Profil nicht sichtbar, und es ist kein Arbeitsordner eingestellt"Not visible in the profile, no working folder set": you ran scopeshelf shell in a folder outside the grants. Either cd to a granted folder, or pass --cd <folder> to make that folder the workspace.
Arbeitsordner … ist im Profil nur lesbar"Working folder is read-only in the profile": the folder is in the read-only grants, so the shell cannot write there. Change the grant in the launcher if it should.
zsh: command not found: scopeshelfThe command line tool is not installed or its folder is not in your PATH. Settings → Command line tool shows the exact line to add. Inside a sandboxed shell the command is always available; this only concerns your normal shell.
command not found: node (or claude, bun, cargo …) inside the shellThe tool lives in a folder under your home directory that is not granted. Edit launcher → step 4, Shell → tick it under Program folders.
Bare prompt, no aliases, no themeStartup files are not ticked, or Login shell is off. Tick ~/.zshrc and friends.
Start shell does nothing, or Not authorized to send Apple eventsScopeShelf may not control your terminal yet. System Settings → Privacy & Security → Automation → ScopeShelf → allow iTerm / Terminal.
Shell ist setuid und kann in der Sandbox nicht startenThe chosen shell program is itself setuid. Pick another under Program.

Something missing on this page? Tell us, and we add it.