# sandboxed.sh runs the agent, Orb holds the conversation

> A self-hosted Rust orchestrator that keeps coding agents on machines you control, with a Tauri desktop client and a SwiftUI iOS app reading the same project record, and three deliberately different execution modes behind them.

**Th0rgal/sandboxed.sh** — Safe runtime for autonomous on-chain AI agents: isolated sandboxes, Library skills, encrypted secrets.

- Repository: https://github.com/Th0rgal/sandboxed.sh
- Website: https://sandboxed.sh
- Stars: 513 · Forks: 53
- Language: Rust
- License: not declared
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/th0rgal-sandboxed-sh

## Three places an agent can run, and only one of them is yours

The mode table is the fastest way to understand the product, because the three rows have three different owners of the compute. Your computer is a local coding agent on your desktop: you pick New Agent, then this computer, then a harness and a model, and the agent works with your local files and tools. Your private cloud means machines you add to sandboxed.sh yourself, which you then select in Orb, and the agent runs either in the configured host workspace or in an isolated container workspace. Cloud agents hand the work to a provider: ChatGPT, Grok Bot or Cursor Cloud, and from Orb you continue that provider's conversation rather than starting a new one. What sits behind those connectors differs more than the menu suggests. ChatGPT uses a signed-in browser profile and the subscription modes your account actually has, Grok Bot uses its connected account, and Cursor Cloud uses its official API with a repository, a Git reference and an available model. Two of the three, ChatGPT and Grok Bot, are labelled experimental, and the models and actions on offer depend on the connected account. One menu entry, three billing and trust stories.

## Orb is the client, the Rust backend owns the record

The architecture note is short and does the load-bearing work: Orb is the client, sandboxed.sh is the execution and persistence layer. Desktop Orb is Tauri with SolidJS, the iOS app is SwiftUI, and both connect to the same sandboxed.sh server, so a phone can browse projects, follow agents, start remote or cloud work and view or edit shared Markdown files. Agents never run on the phone; local desktop execution still depends on the computer that owns the run. What the Rust backend owns is projects, missions, event history and remote-node coordination, and cloud adapters observe provider work independently of whichever client window is open, so closing Orb does not stop an agent. A project holds folders, conversations and shared context, and a mission is the unit you open to follow progress, send a follow-up, change supported model settings or review output, with Markdown, code, tables, LaTeX, images and downloadable artifacts kept readable inside the conversation. Automation does not need Orb at all, because the same control plane is also reachable over MCP for coordinators such as Hermes, and it reads and writes the same project and mission records rather than a parallel set.

## Cargo.toml says 1.3.0 while the newest tag is v0.12.0

Reconcile the version numbers before you plan an upgrade. In Cargo.toml the crate declares version 1.3.0 with edition 2021 and rust-version 1.91, while the published releases top out at v0.12.0 from May 2026, preceded by v0.11.5 and v0.11.1. Two numbering schemes are in play and the documentation does not explain how they map, so pinning a release tag and pinning the crate are separate decisions. Nobody has to guess the toolchain: the container build uses rust:1.91-bookworm, and a host without that compiler cannot produce the binaries. Commits tell a healthier story than tags do. On the default branch master the repository is not archived, and the last push landed on 2026-10-01, so the work is moving while the newest published tag sits four to five months back. Looking at the top-level layout also tells you this is several products in one repository: a Tauri orb directory, a SwiftUI ios_dashboard, a Next.js dashboard, an android_dashboard, a docs-site, a vercel.json and a skills directory beside the Rust src.

## Five binaries come out of one cargo build

The Dockerfile compiles several executables in one pass and copies them out together, named through a single build argument: sandboxed-sh, desktop-mcp, workspace-mcp, automation-manager-mcp and sandboxed-mcp. Four of those five are MCP servers, which matches the claim that the same control plane is available over MCP for coordinators. Coupling to the rest of the tree is unusual here. build.rs reads the catalog directory, and the sources include shared/*.rs plus some files from scripts through path attributes and include_str, so a build can fail for reasons that have nothing to do with Rust when the catalog or a script is absent. A second stage switches toolchain entirely: an oven/bun:1 image installs the dashboard from a frozen lockfile, and NEXT_PUBLIC_API_URL is left deliberately empty because a Caddyfile proxies the API path to the backend at run time instead of baking an origin into the bundle. Both stages then land in one image that serves the Rust service and the web dashboard together.

## The host publishes 3000, the container listens on 80

The compose file is the shortest description of the deployment shape. One service built from the repository root, restart unless stopped, a single published mapping of port 3000 to port 80, and two named volumes, sandboxed-data on /root/.sandboxed-sh and claude-auth on /root/.claude. The host port and the in-container port are therefore not the same number, which matters the moment you write a firewall rule or an SSH tunnel. An SSH mount is present but commented out, and the comment gives the reason: private git repositories for the Library need it, and it is mounted read-only. The same block leaves privileged true and cgroup host commented out, and those two lines are the switch for systemd-nspawn container workspaces, so the isolation your deployment gets changes the moment you uncomment them. An optional environment file is declared as a path of .env with required set to false, which means the service starts without it and falls back to whatever defaults the image carries.

## Defaults that decide how much runs at once

The shipped .env.example is where the operational limits are visible, and several of them are conservative or permissive by design. MAX_PARALLEL_MISSIONS is 1, so one mission runs at a time unless you raise it, MAX_ITERATIONS caps the loop at 50, and STALE_MISSION_HOURS of 24 is what marks an abandoned mission as stale. WORKING_DIR is /root and LIBRARY_PATH is /root/.sandboxed-sh/library, and when LIBRARY_REMOTE is unset the code falls back to the official sandboxed-library-template.git repository, with the dashboard Settings page preferred over the variable. OPENCODE_BASE_URL points at a local OpenCode backend on port 4096, and OPENCODE_PERMISSIVE ships as true, which is the first line to read in any deployment that is not a private experiment. Two settings are conditional: TOOL_STUCK_ABORT_TIMEOUT_SECS of 0 disables the stuck-tool abort entirely, and OPENCODE_CONFIG_DIR is only needed when the OpenCode service runs in strong skill isolation mode.

```bash
OPENCODE_BASE_URL=http://127.0.0.1:4096
OPENCODE_PERMISSIVE=true
MAX_ITERATIONS=50
STALE_MISSION_HOURS=24
MAX_PARALLEL_MISSIONS=1
```

Dependency choices explain the rest of the shape. jsonwebtoken handles auth, aes-gcm with pbkdf2 and sha2 covers encrypted secrets, rusqlite runs bundled for local storage, portable-pty handles processes on Unix, sysinfo reports system metrics, zip handles backup and restore, croner schedules, and sd-notify sends systemd readiness and watchdog notifications while staying a no-op off systemd.

## The proxy routes inference and does not sign you in

Bringing your own subscription is a routing decision rather than a login. You connect supported subscription accounts through CLIProxyAPI Plus, a maintained fork, and then configure that endpoint as an inference provider inside sandboxed.sh. The proxy handles account routing and rotation among configured, eligible accounts, while Orb only lets you choose the harness and the model, and provider quotas still apply on top of that. The limits are stated rather than left to be discovered: managed cloud agents use separate service adapters, and connecting a proxy account does not sign in to the ChatGPT browser profile or create a Cursor Cloud API account. Credential ownership has its own document, docs/CREDENTIAL_OWNERSHIP.md, which is the file to read before pointing a proxy at accounts that matter to you. The upstream CLIProxyAPI is linked separately from the fork, so the two are distinct projects with distinct maintainers, and the choice between them is a maintenance decision rather than a feature one.

## Where this is the wrong shape

The scope is broad but the boundary is real. If you want one agent run on your laptop with no server to look after, Orb on its own is the lighter choice and the orchestrator is overhead. If your work belongs entirely on provider infrastructure, the cloud agent mode already covers it without the Rust service. And if you cannot accept a process that holds a JWT signing path, an encrypted secret store and, once you enable it, SSH keys for private repositories, then the security posture this project is built around is the reason to pass. One more thing to weigh before you evaluate it: the repository description frames the product around autonomous on-chain AI agents, while the README describes a coding-agent orchestrator formerly known as Open Agent. The crate name, the build layout and the documentation are all about running coding harnesses, so judge it on that.

## Conclusion

sandboxed.sh earns its keep when agents have to run on infrastructure you own while the people driving them work from a browser, a desktop app or a phone, and when the records of what an agent did have to outlive the session that started it. Skip it for a single local agent run, or when your work belongs entirely on a provider's own infrastructure. Before deploying, check three things: whether the orchestrator runs in Docker or natively, because the host port 3000 maps to port 80 in the container; what OPENCODE_PERMISSIVE and MAX_PARALLEL_MISSIONS are set to, since the defaults are permissive and serial; and how your model inference is routed, because the CLIProxyAPI path handles accounts in a way that is not the same thing as signing in to ChatGPT.

## FAQ

### What is sandboxed.sh?

It is a self-hosted Rust orchestrator for AI coding agents, formerly called Open Agent. It owns projects, missions, event history and remote-node coordination, while Orb is the desktop and iOS client you use to start work and follow it.

### Where do agents actually run in sandboxed.sh?

In one of three modes: a local coding agent on your desktop, an agent on a remote machine you added to sandboxed.sh, or a provider-managed cloud agent such as ChatGPT, Grok Bot or Cursor Cloud whose conversation you continue from Orb.

### Do I have to use Orb to run agents with sandboxed.sh?

No. The same control plane is available over MCP for coordinators such as Hermes, and automation uses the same project and mission records that Orb reads, so a script and the desktop client see the same state.

### How do I install sandboxed.sh?

Follow the Docker guide in docs/install-docker.md or the native Linux guide in docs/install-native.md. The compose file builds one image, maps host port 3000 to container port 80, and keeps data in a sandboxed-data volume mounted at /root/.sandboxed-sh.

### Can I use my own ChatGPT subscription with sandboxed.sh?

You can route model inference through CLIProxyAPI Plus by configuring that endpoint as an inference provider, and the proxy rotates among eligible connected accounts. That is not the same as signing in to the ChatGPT browser profile used by the ChatGPT cloud agent connector.

## Sources

- [Issues](https://github.com/Th0rgal/sandboxed.sh/issues)
- [Project website](https://sandboxed.sh)
- [README](https://github.com/Th0rgal/sandboxed.sh/blob/master/README.md)
- [Releases](https://github.com/Th0rgal/sandboxed.sh/releases)
- [Th0rgal/sandboxed.sh on GitHub](https://github.com/Th0rgal/sandboxed.sh)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/th0rgal-sandboxed-sh
