Sandbox and networking

Osprey runs without operating-system isolation by default. Pass --sandbox after osprey or osprey agent to request an isolated base-tool lane.

The sandbox complements tool approvals and filesystem path checks. The sandbox does not isolate the complete Osprey process.

Platform behavior

Platform --sandbox backend Filesystem behavior Network behavior
macOS Seatbelt through /usr/bin/sandbox-exec The sidecar can read and write the workspace and its session temporary directory. Outbound traffic is denied by default except loopback.
Linux Landlock plus seccomp The sidecar receives a Landlock filesystem ruleset and a seccomp deny filter. Outbound traffic remains open.
Other systems No authoritative backend Osprey creates no accepted sandbox lane. Launch fails before the agent starts.

Osprey provisions one agent-runner sidecar against the current working directory. The sidecar reports an isolated execution posture. Osprey rejects any lane with an unsandboxed posture.

A malformed workspace .osprey.toml file stops sandbox creation. A sidecar startup or health-check failure also stops launch. Failure paths destroy any sidecar that already started. Normal teardown kills the sidecar. It also removes the session temporary directory.

macOS Seatbelt policy

The macOS profile grants read and write access to the actual workspace. Osprey does not create a scratch worktree for the sandbox. The profile also grants the access needed for agent-runner and its session temporary directory.

The base profile denies outbound networking except loopback. The sidecar uses the gRPC protocol for remote procedure calls over loopback.

Add explicit destinations in the workspace root .osprey.toml file:

[sandbox.network]
allow = ["api.example.com:443", "registry.example.com:443"]

Each entry must contain one literal host:port pair. Schemes, wildcards, credentials, spaces, and Internet Protocol version 6 literals are unsupported. The port must be between 1 and 65,535.

Osprey resolves each hostname while building the Seatbelt profile. The profile receives one numeric rule for each resolved address. A malformed entry or Domain Name System (DNS) failure stops sandbox creation. The generated rule does not follow later DNS changes during the session.

Linux Landlock and seccomp

The Linux sidecar applies Landlock to its workspace and session temporary directory. The sidecar also applies a seccomp filter before serving tool requests.

Landlock grants read, write, and execute access inside the workspace and session temporary directory. Landlock grants read and execute access to required system binary and library directories. The ruleset grants read access to /etc and required access to selected terminal and random-data devices. Denied paths include /home, /root, /proc, /sys, and block devices.

Seccomp returns EPERM for power, mount, swap, kernel-module, and low-level input-output permission system calls. The Linux confinement build supports x86_64 and aarch64.

Linux network egress remains open. Landlock does not restrict networking. Blocking socket creation also breaks the loopback gRPC server.

The [sandbox.network].allow list has no enforcement effect on Linux. When the list is non-empty, Osprey writes one warning per process. Do not treat the macOS allowlist as a portable network policy.

Use container, virtual-machine, or host firewall policy when Linux network isolation is required. Osprey does not configure external isolation controls.

Isolated base tools

With --sandbox, Osprey replaces the local base dispatcher with a gRPC dispatcher. The sidecar advertises exactly eight tools:

  • read_file
  • list_directory
  • grep
  • write_file
  • edit_file
  • bash
  • find_files
  • tree

The sidecar omits process, todo_write, switch_persona, task_status, web_fetch, web_search, lsp, and retrieve from the base catalog. The remaining orchestration layers can add other host-side tools. Although web_search and lsp run through the local dispatcher when unsandboxed, sandbox replacement removes both tools.

Sidecar file requests resolve relative to the workspace root. Read paths must exist and remain inside the canonical workspace. Write paths can be new, but their first existing ancestor must remain inside the workspace. Symlink and parent-directory escapes are rejected. Bash working directories must also remain inside the workspace.

Allowed roots without the sidecar

The unsandboxed dispatcher makes the canonical current directory its first allowed root. Repeat --allowed-root PATH on osprey agent to add more roots. Osprey canonicalizes every added root during startup. An added path that cannot be canonicalized produces a log message. Osprey skips that path.

Local reads canonicalize the requested target before the allowlist check. Local writes canonicalize the first existing ancestor and normalize the new suffix. The local checks reject parent traversal and symlink escapes.

The sandbox sidecar uses one workspace root instead of the local dispatcher's root list. --allowed-root does not extend the sidecar workspace. Use an unsandboxed run when a task requires an explicit second root. Apply an external isolation boundary before combining unsandboxed mode with --yolo.

Host-side layers

The sandbox wrapper sits below Osprey's other dispatcher layers. The following work remains in the main Osprey process:

  • Skill discovery and load_skill.
  • extension_manage and custom extension subprocesses.
  • Extension lifecycle and tool hooks.
  • Workflow JavaScript execution and workflow bookkeeping.
  • Built-in memory and remote Hindsight memory requests.
  • Interactive questions and session search.
  • Provider calls and model catalog refreshes.

Workflow child agents receive the sandboxed base dispatcher when the parent has a sandbox lane. The workflow engine and its ledger still run on the host. Subagents share the parent's sandbox handle for their base tools. Their session storage and orchestration also remain on the host.

An extension manifest accepts an execution field named sandbox. The current custom-tool dispatcher does not read the sandbox field. Custom extension programs therefore run directly on the host even when the field is true.

Extension hooks also run on the host through sh -c. A hook timeout kills its process group. A hook spawn failure produces a warning and allows the intercepted action. Parse failures, timeouts, and unexpected exits have the same behavior. An exit status of 2 with standard error blocks the action.

The composition boundary makes --sandbox base-tool isolation, not whole-agent isolation. Review active extensions, workflows, and memory configuration before relying on the lane.

Approval interaction

Sandboxing does not select an approval policy. The interactive terminal user interface (TUI) defaults to on-request. The headless command defaults to deny-untrusted.

--yolo selects the never policy. Osprey permits --yolo without --sandbox. It writes a warning. In unsandboxed --yolo mode, every non-hardline tool request proceeds without an Osprey prompt. External isolation is the caller's responsibility.

The hardline floor checks every bash call before policy evaluation. The floor blocks the following catastrophic command shapes:

  • System power commands such as shutdown, reboot, poweroff, and halt.
  • Recursive forced removal of a root target.
  • Any rm command with --no-preserve-root.
  • mkfs commands that target a device path.
  • dd output that targets a device path.

The matcher handles common wrappers, shell separators, command substitution, subshells, and bash -c or eval nesting. The matcher compares parsed tokens and binary basenames instead of substrings. The matcher stops recursive analysis after four nested levels. The hardline floor blocks only the listed command shapes. It is not a general shell security parser.

Network paths outside the sidecar

Model providers receive prompts, tool definitions, conversation context, and selected attachments through their configured application programming interfaces. Available providers are Anthropic, OpenAI, OpenRouter, Nous, and the experimental Z.AI Coding Plan. Environment variables supply provider credentials.

web_fetch uses a guarded host client in unsandboxed mode. The guard accepts only Hypertext Transfer Protocol (HTTP) and Hypertext Transfer Protocol Secure (HTTPS) Uniform Resource Locators (URLs). The guard rejects URL credentials, credential-like query keys, and non-public destinations. Every redirect and every resolved address receives another guard check.

The fetch tool accepts at most five URLs per call. Each response has a five-mebibyte body limit and a 120-second maximum timeout. The tool does not extract Portable Document Format content.

In an unsandboxed run, web_search uses Exa, Brave, or SearXNG when configured. Search providers use their configured host endpoints without the model-supplied URL guard. Search requests have a 15-second timeout and a five-mebibyte response limit.

The optional Hindsight memory provider sends recall and store requests to its configured endpoint. Cloud mode requires HINDSIGHT_API_KEY. Hindsight does not support edit or remove operations.

The model catalog can contact models.dev and the configured Nous catalog endpoint. TUI startup reads only the existing cache. Later refresh effects and the setup wizard can request both catalogs.

Current sandbox differences and failure semantics

The sandbox grep schema advertises ignore_case, literal, context, and limit. The gRPC request currently sends only pattern, path, and file_glob. The four additional options have no effect in the sandbox lane.

Sandboxed bash collects standard output, standard error, exit code, signal, and timeout diagnostics. If the gRPC call completes, the dispatcher classifies the tool result as success. A nonzero command exit therefore appears as success with diagnostic text.

The success classification differs from the local dispatcher. The difference prevents failure-based approval, retry, and no-progress logic from observing the nonzero result as a tool failure. Treat the diagnostic text as authoritative when reviewing a sandboxed command result.

The sidecar omits task_status, but interactive completion uses declared task_status claims. Substantive sandboxed TUI tasks therefore cannot declare done or blocked through task_status.

The sidecar also omits retrieve when semantic tool-result compression is active. A compressed result can contain a retrieval marker without an advertised retrieval tool. Disable semantic tool-result compression for sandboxed runs that require full-output recovery.

An unauthenticated sidecar response triggers one credential refresh and one retry. A missing refresh token or failed retry returns a non-retryable tool failure. Other gRPC failures also return non-retryable tool failures.

The read_file sidecar marks content truncated after 2,000 lines. Search and tree responses also carry backend truncation markers. The sandbox dispatcher does not attach local process metadata to tool results.

Back to Osprey