Bare Agent vs. Sandboxed Agent: Where the Permission Surface Differs
When a human developer SSHs into a Mac, they usually know not to delete ~/.ssh or export Distribution certificates. AI Agents behave differently—frameworks that invoke shell, file, and network tools inherit the full privileges of the current macOS user by default. An Agent tasked with "scan the repo for TODOs and output a Markdown report" theoretically needs read access to the project directory and one output file; in practice it can reach Keychain, browser cookies, and arbitrary outbound HTTP requests.
Containerization isolates processes, but on macOS it sacrifices the full Xcode toolchain and Apple-native frameworks; rebuilding a VM per task is too slow for interactive Agent loops. OpenClaw takes a third path: on real macOS, YAML policies make allow/deny decisions at the syscall layer, and every decision is written to an audit stream. The Agent can still use the M4's 38 TOPS Neural Engine for local inference, but out-of-policy reads and writes are blocked immediately.
The demo task in this post is deliberately narrow: run a static scan on an existing code snapshot inside the sandbox (rg for TODO/FIXME), attempt a git clone that policy will reject, then write the report under /workspace. Success criteria: the script completes, audit logs show both allow and deny events, and you can trace each event back to the YAML rule that fired.
Hardware: JexMac Japan (Tokyo) node · Mac mini M4 · 10-core CPU · 16 GB unified memory · 256 GB NVMe · 1 Gbps dedicated bandwidth. OS: macOS 15 Sequoia. OpenClaw CLI 0.9.x, policy format v2. Entire walkthrough via SSH; system extension approval requires one brief VNC login.
Before You Start: Four Prerequisites to Verify Once
Your local laptop can be Windows, Linux, or macOS—as long as you have an SSH client. But missing any of the four items below will stall the flow midway.
- Delivered JexMac instance: Console "Access Info" shows SSH address and port. Five nodes—Singapore, Japan (Tokyo), Korea (Seoul), Hong Kong, US East—same specs and pricing; for Agent experiments, pick the region closest to your target API latency.
- OpenClaw instance-token: Generated on first enable under console "Security & Sandbox", format like
oct-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. Shown once—store immediately in 1Password, Bitwarden, or equivalent. - Working directory
/workspace: Create on the host beforehand; the sandbox maps this path as the Agent's read/write zone. Do not put private keys or p12 files here. - At least one policy YAML: Section 5 provides a read-only template; principle is start strict, loosen based on deny logs—not guess permissions upfront.
Enable OpenClaw in the Console and Store the instance-token
OpenClaw is not on by default—each physical instance is controlled independently, so workloads that don't need audit don't pay the overhead. Three browser steps below; everything else happens over SSH.
-
01
Instance detail → "Security & Sandbox"
Log into the JexMac console, open the target Mac mini instance, find the OpenClaw toggle. If the instance just delivered (within 1–5 minutes), wait until status shows Running before proceeding.
-
02
Enable and copy the token
Click enable; a dialog shows the
instance-token. After confirming it's saved in your secrets manager, click "I've saved it, continue." Never paste the token into Slack, tickets, or Git commits. -
03
Confirm badge shows "Enabled"
If status stays "Enabling" for 30+ seconds, refresh the page. Once the green badge appears, close the browser—CLI handles the rest.
Install CLI over SSH and Run Three-Component Health Checks
After SSH login, the install script detects Apple Silicon and typically finishes within 30 seconds on M4.
curl -fsSL https://api.jexmac.com/openclaw/install.sh | bash
openclaw auth login --token <instance-token>
openclaw status
openclaw status must show all three components as healthy:
| Component | Role | Expected State |
|---|---|---|
| Policy Engine | Parse YAML, allow/deny before syscalls | healthy |
| Sandbox Runtime | Sandbox lifecycle, process isolation, directory mapping | healthy |
| Audit Bus | Async audit event writes, non-blocking on Agent hot path | healthy |
If any component is degraded or unavailable, run openclaw doctor first. Common cause: system extension pending approval after first install—connect via browser VNC, open System Settings → Privacy & Security, allow OpenClaw, then restart the CLI service over SSH. Policy Engine healthy means the process is up, not that your YAML is valid—policy validation is a separate step in the next section.
Least-Privilege Policy: A Version-Controlled YAML
The policy file defines which paths the Agent can read, which processes it can spawn, and whether outbound network is allowed. Recommended workflow: first YAML opens only the minimum required for the task → run the task → inspect deny logs → add allow rules as needed—not start wide open and tighten later.
Save the following as ~/policies/agent-readonly.yaml:
apiVersion: openclaw.jexmac.com/v2
kind: SandboxPolicy
metadata:
name: agent-readonly
spec:
filesystem:
allow:
- path: /workspace
access: [read, write]
deny:
- path: "**/Keychains/**"
- path: "**/.ssh/**"
- path: "**/Library/Cookies/**"
process:
allow: [git, rg, python3, zsh, bash]
network:
egress: deny-all
Three design points: deny takes precedence over allow—even if /workspace is writable, paths in the deny list are still blocked; process.allow is a process-name whitelist—if the Agent needs node or npm, add them explicitly or you'll get E_POLICY_DENY: process; egress: deny-all deliberately blocks git clone in this demo so you can see network deny events in the audit stream.
Validate syntax before creating the sandbox:
openclaw policy validate -f ~/policies/agent-readonly.yaml
Expected output: policy valid (0 warnings); misspelled fields or v1 legacy format report specific line numbers.
Create the Sandbox, Submit an Agent Task, Verify Results
Before wiring LangGraph or similar frameworks, run a deterministic shell script to close the loop—predictable behavior makes it easy to tell "policy issue" from "Agent logic issue" when something fails.
Create entry script /workspace/agent-entry.sh on the host:
#!/bin/zsh
set -euo pipefail
cd /workspace
git clone --depth 1 https://github.com/apple/swift-sample-code.git repo 2>/dev/null \
|| echo "clone blocked (expected)"
rg -rn "TODO|FIXME" . --glob '*.swift' > scan-report.txt 2>/dev/null || true
echo "Scan complete: $(wc -l < scan-report.txt | tr -d ' ') matches" > summary.txt
cat summary.txt
After chmod +x /workspace/agent-entry.sh, run in order:
-
01
Create sandbox
openclaw sandbox create --name agent-demo --policy ~/policies/agent-readonly.yamlReturn status
readyis sufficient. Duplicate create with the same name prompts "already exists"—won't destroy data. -
02
Open a second SSH session, tail audit live
openclaw audit tail --sandbox agent-demo --followDecision events typically appear within 50–200 ms after the operation.
-
03
Execute script inside sandbox
openclaw sandbox exec agent-demo -- /bin/zsh /workspace/agent-entry.shExpected output includes
clone blocked (expected);summary.txtshould contain the scan line count. -
04
Stop sandbox
openclaw sandbox stop agent-demo/workspacedata persists on the host; add--rmfor full cleanup.
Because outbound network is denied, git clone won't succeed—that's intentional, to produce a verifiable network deny. If the rg step completes, filesystem allow rules are correct. On the Tokyo node we measured ~2.6 seconds end-to-end; policy overhead is negligible.
Audit Log Fields: Reading from Allow to Deny
Audit is not a post-hoc PDF report—it's an event stream synchronized with policy decisions. Typical allow record (reading the entry script):
ts=2026-07-28T09:03:12.481Z
sandbox=agent-demo
syscall=open
resource=filesystem
path=/workspace/agent-entry.sh
access=read
decision=allow
policy_rule=filesystem.allow[0]
latency_us=34
policy_rule points to the YAML rule index that fired; latency_us is decision latency in microseconds. Corresponding network deny (blocked clone):
ts=2026-07-28T09:03:12.512Z
sandbox=agent-demo
syscall=connect
resource=network
dst=140.82.113.4:443
decision=deny
policy_rule=network.egress.deny-all
latency_us=19
If production tasks need GitHub access, change network.egress to allow-list and add github.com:443, validate, then run openclaw sandbox update --name agent-demo --policy ~/policies/agent-readonly.yaml—no need to destroy and recreate the sandbox.
Common queries:
- Denies in the last hour:
openclaw audit query --decision deny --since 1h - Filter by path:
openclaw audit query --resource filesystem --path "/workspace/**" - Export JSON for SIEM:
openclaw audit export --sandbox agent-demo --since 24h --format json > audit.json
Six Frequent Errors and Shortest Fix Paths
| Symptom | Root Cause | Fix |
|---|---|---|
auth login token invalid |
Copied with trailing space, or token rotated | Re-copy from console; on macOS use pbpaste | xxd to check leading/trailing bytes |
status shows unavailable |
System extension not approved | VNC → System Settings → Privacy & Security → Allow OpenClaw → restart service |
policy validate unknown field |
YAML field typo or v1 format | Confirm apiVersion: openclaw.jexmac.com/v2 |
E_POLICY_DENY: filesystem |
Accessed path outside allow list | audit query --decision deny for path, add to filesystem.allow |
E_POLICY_DENY: process |
Spawned process not on whitelist | Check deny with resource=process, add process name to process.allow |
git clone times out, no deny log |
DNS blocked before connect reached | Switch network policy to allow-list; also allow 8.8.8.8:53 or domain rules |
instance-token is equivalent to high-privilege instance credentials—never commit it to .env or Git. Production setups should assign zero-trust device certificates and roles (viewer / operator / admin) per team member instead of sharing one token.
After PoC: Where Should Agents Run Long-Term?
A read-only sandbox proof is only the starting point. Real workloads may call xcodebuild, pull from npm/PyPI, or spin sandboxes up and down per PR in CI—the scaling path is always iterate policy from deny logs, not guess permissions.
On compute: a single Mac mini M4 · 16 GB can run two build sandboxes with DerivedData in parallel, leaving ~4 GB for OpenClaw audit and system services. When load grows, JexMac's Thunderbolt 5 cluster service links multiple Mac minis at 80 Gbps—each instance keeps independent policy and audit storage.
If your team lacks a dedicated cloud Mac, common alternatives each have clear gaps: running Agents 24/7 on a local MacBook interferes with daily dev and sustained load heats the machine; GitHub-hosted macOS Runners share a resource pool with no native OpenClaw integration—peak queues hurt interactive Agents; buying your own Mac mini means procurement lead time, colocation, and on-site certificate rotation.
JexMac offers dedicated physical Mac mini M4 (10-core · 16 GB · 256 GB NVMe · 38 TOPS), OpenClaw built into standard instances, five nodes each with dedicated public IPv4 and 1 Gbps bandwidth, 1–5 minute delivery after payment, from $21.5/day and $107.3/month with no contract lock-in. Rent daily for Agent experiments; switch to monthly once policies stabilize.
Run Your First Agent in an Isolated macOS Environment
Every command in this post was verified on dedicated JexMac Mac mini M4 physical nodes. Provision an instance → enable OpenClaw → submit a task with the policy above—you can see your first audit record within an hour. Daily rental from $21.5; release anytime after PoC.