Sandstorm: self-hosted Claude agents with Slack, multi-provider LLMs and OTel traces
Run Claude agents in secure cloud sandboxes — via API, CLI, or Slack. One call. Full agent. Zero infrastructure.
At a glance
- What is it?
- Sandstorm is a Python runtime that runs Claude Agent SDK style agents in per-thread sandboxes, exposed through a CLI, an HTTP API, a Python client and a Slack bot. Its selling point is where it runs and what it emits, not the agent loop itself.
- Who is it for?
- Adopt Sandstorm if you need agent runs inside your own network, want non-Anthropic models behind the same runtime, or already export traces to Langfuse, Phoenix or Langsmith and refuse a closed console. Do not adopt it if you want a hosted service with no operational surface, or if your agents must run on Anthropic-managed infrastructure.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 144 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The gap Sandstorm is aimed at
Two products shipped in April 2026 that Sandstorm's README positions itself between. Anthropic's Claude Managed Agents gives a sandbox, but only on Anthropic infrastructure and only for Claude models. Vercel's Slack Agent Skill plus Chat SDK gives a Slack integration, but only on Vercel and only in TypeScript. The README lists three things it says only an open source project can do: self-host so runtime traffic stays inside your network, run models other than Claude, and export telemetry to a backend you already operate. That is the whole pitch. It is not a better agent loop; it is the same class of agent loop placed where you control the network boundary, the model choice and the trace sink. The audience follows from that: teams who cannot send runtime traffic to Anthropic or Vercel, engineers on GPT-5, Gemini, DeepSeek, Qwen, Kimi or Grok who still want the tool, skill and sandbox model, and anyone running Langfuse, Phoenix or Langsmith who does not want agent telemetry locked in a vendor console. If none of those three constraints applies to you, the project's own framing suggests you are not the target.
One runtime, five entry points
The architecture claim in the README is that a CLI, an HTTP API, a Python client, a Slack bot and a repo-local TypeScript client all sit over the same runtime. That single-runtime design is what makes the rest coherent: a run started from Slack and a run started from the command line should hit the same execution path, which is why the README can show a CLI transcript and a Slack transcript of the same research task side by side. The unit of isolation is the thread. Each Slack thread keeps its own paused sandbox on the configured runtime, E2B by default, so uploaded files, generated outputs and installed packages persist across messages and, according to the documentation, across server restarts. The README describes that continuity as real and points to docs/memory.md. This is the mechanism that separates Sandstorm from a stateless bot wrapper: the sandbox is not torn down between turns, it is paused and resumed, so a follow-up message in the same thread continues in the same filesystem. The run output carries the accounting you would want from that model: model name, turn count, cost and duration, as shown in the README's example line reading success with 14 turns and a cost of $0.0731, plus a list of artifacts written into the sandbox.
Getting from pip install to a first run
Installation is a single package, duvo-sandstorm, and the quickstart is four commands. The README gives them literally: pip install duvo-sandstorm, then ds doctor to verify credentials before running anything, then ds init research-brief, then cd into that directory and pass a prompt to ds. The doctor step is the one worth keeping in your own notes. The README states it is the fastest way to catch a missing ANTHROPIC_API_KEY, a missing E2B_API_KEY or a Slack scope problem before your first real query, which tells you those three things are the expected failure points at setup time. Slack is an extra: pip install "duvo-sandstorm[slack]", then ds slack setup, which the README describes as interactive and which opens the Slack app install in your browser, then ds slack start for Socket Mode during development, with an --http flag for production. Python 3.11 or newer is required, per the badge in the README. Nothing here needs a config file to be written by hand for the basic path; the CLI creates the project directory and the runtime picks up credentials from the environment. The documentation does not, in the material available, specify the full set of environment variables beyond the two API keys and the Slack scopes, so treat ds doctor as the authority on what is missing rather than a checklist you assemble yourself.
Slash commands, memory scopes and reaction triggers
The Slack surface is where most of the version 0.9.1 work landed. Beyond the basic mention trigger, there are slash commands with three distinct memory scopes: /remember for a personal memory, /team-remember for a workspace-wide one, and /channel-remember for a channel-scoped one. /cancel stops the most recent in-flight run in the channel, and /model takes a model identifier such as claude-haiku-4-5-20251001 to override the model for that thread. Reaction triggers let an emoji on any message fire an agent run. The App Home tab shows memories, active runs, channel defaults and triggers. Triggers are configured as a JSON array with three types. A cron trigger takes a schedule in standard cron form, and the README notes that sub-hourly cron is supported where Claude Code Routines enforces a one-hour minimum. A webhook trigger takes a path and a secret, with the prompt able to interpolate from the request body using a placeholder syntax like {{body.issue.title}}. A reaction trigger names an emoji and can interpolate the message text. The interpolation syntax is the part to look at closely: prompts are templates over incoming payloads, which means the trigger configuration is also where untrusted input enters the agent prompt, and the README does not describe any sanitisation step in the material provided.
Per-thread sandboxes are the design assumption, and the constraint
The default runtime is E2B, and the README is explicit that the default E2B runtime is available self-hosted. That is a meaningful distinction from Anthropic's managed offering, but it does not mean Sandstorm removes the dependency. A fresh sandbox per thread on a hosted runtime means your agent's filesystem lives with that provider unless you change the runtime, and the material available does not document which other runtimes are supported or how to swap them. The paused-sandbox model also has a cost profile you should reason about before adopting: every thread holds a sandbox, and the README does not state an eviction policy, a maximum number of concurrent paused sandboxes, or what happens to a thread's sandbox when the workspace hits a limit. If your Slack workspace has hundreds of low-traffic threads, the number of simultaneously paused sandboxes is the number that determines your bill and possibly your quota. The README gives per-run cost in the example output, which is useful for reasoning about active runs, but it says nothing about the cost of idle paused sandboxes. That is the single biggest unquantified item in the material, and it is the first thing to measure on your own workspace before rolling this out broadly.
Where it is the wrong tool
Sandstorm is not a fit if you want an agent platform you do not operate. The README's own comparison table lists self-hosted as a Sandstorm advantage over both managed alternatives, which is honest positioning but also a clear statement of the operational burden: you run the service, you hold the API keys, you manage the Slack app, and you keep the sandbox runtime reachable. A team without anyone who wants to own a long-running Python service and a Slack app installation should pick a hosted option instead. It is also the wrong tool if your requirement is that agent execution happens on Anthropic-managed infrastructure for compliance reasons, since the project exists precisely to avoid that. And it is a poor fit if you need the agent to operate on a persistent shared filesystem across many users; the model here is a sandbox per thread, which is isolation rather than collaboration. Finally, the version history in the material shows v0.9.2 as a re-ship of v0.9.1 because of a CI retry, which is a normal release-engineering event but also an indicator that the project is still pre-1.0 and its release process is settling. Treat the API and the Slack command surface as things that can move between minor versions.
The real alternative, and where the approaches diverge
The closest comparison in the README's own table is claude-code-slack-bot, and the difference is the one that matters most for this decision. Both are MIT licensed and both are self-hosted, but claude-code-slack-bot is marked as not sandboxed per thread, and it is Claude-only with no OTel export. So the choice is not open source versus closed source; it is whether you need isolation and telemetry. If you are running Claude Code in Slack on a machine you already trust, with users you already trust, and you do not need traces in an external backend, the simpler bot is a smaller thing to operate and Sandstorm's per-thread sandbox adds a dependency and a cost line you would not otherwise have. Sandstorm earns its extra surface when the sandbox is doing real work: untrusted prompts, code execution, file uploads from Slack users, and a requirement that you can see what happened afterwards in Langfuse, Phoenix or Langsmith rather than in a vendor console. The multi-provider angle is a second, independent reason to choose it, and it is genuinely different from both managed alternatives, which the README describes as Claude-only. If you are on GPT-5 or Gemini and want the Claude Agent SDK's tool and skill model anyway, there is no equivalent in the managed options listed.
Licence, maintenance and what to verify first
The project is MIT licensed, which permits commercial use and modification and carries no copyleft obligation on your own code. That is the least restrictive of the options in the README's comparison table, where Anthropic's managed agents are proprietary and Vercel's offering is described as Apache templates. MIT does not, however, say anything about the terms of the sandbox runtime you point it at, and if you use the default E2B runtime you are bound by E2B's terms separately. The same applies to whichever model provider you configure. On maintenance: the last push recorded is 2026-04-24 and the most recent release is v0.9.2 from 2026-04-17, with v0.9.0 nine days earlier and v0.8.1 about a month before that. That cadence suggests active development, and the jump from 0.8 to 0.9 carried a substantial Slack feature set (memory scopes, /cancel, reaction triggers, App Home), which means upgrade notes between minor versions are worth reading rather than assuming. The README points to docs/observability.md, docs/triggers.md, docs/memory.md, docs/comparison.md and docs/faq-vs-managed-agents.md; those five files are where the operational detail lives, and the README alone does not cover runtime configuration, sandbox lifecycle limits or the OTLP exporter settings. Verify three things before you commit: that ds doctor passes with your production credentials, that your chosen runtime and model provider are both acceptable under your own data handling rules, and what your paused-sandbox count looks like after a week of real Slack traffic.
Editorial conclusion
Adopt Sandstorm if you need agent runs inside your own network, want non-Anthropic models behind the same runtime, or already export traces to Langfuse, Phoenix or Langsmith and refuse a closed console. Do not adopt it if you want a hosted service with no operational surface, or if your agents must run on Anthropic-managed infrastructure. Before committing, run ds doctor against your real credentials and confirm that E2B is the runtime you can actually use, since a fresh sandbox per thread is the design assumption the whole model rests on.
Community notes