A restricted shell interpreter for Go. Designed for AI agents that need to run shell commands safely.
go get github.com/DataDog/rshellpackage main
import (
"context"
"os"
"strings"
"github.com/DataDog/rshell/interp"
"mvdan.cc/sh/v3/syntax"
)
func main() {
script := `echo "hello from rshell"`
prog, _ := syntax.NewParser().Parse(strings.NewReader(script), "")
runner, _ := interp.New(
interp.StdIO(nil, os.Stdout, os.Stderr),
)
defer runner.Close()
runner.Run(context.Background(), prog)
}Every access path is default-deny:
| Resource | Default | Opt-in |
|---|---|---|
| External commands | Blocked (exit code 127) | Provide an ExecHandler |
| Filesystem access | Blocked | Configure AllowedPaths with directory list |
| Environment variables | Empty (no host env inherited) | Pass variables via the Env option |
| Output redirections | Blocked at validation (exit code 2) | Not configurable — always blocked |
AllowedPaths restricts all file operations to specified directories using Go's os.Root API (openat syscalls), making it immune to symlink traversal, TOCTOU races, and .. escape attacks.
See SHELL_FEATURES.md for the complete list of supported and blocked features.
Linux, macOS, and Windows.
900+ YAML-driven test scenarios cover builtins, shell features, and security restrictions.
tests/scenarios/
├── cmd/ # builtin command tests (echo, cat, grep, head, tail, uniq, wc, ...)
└── shell/ # shell feature tests (pipes, variables, control flow, ...)
By default, each scenario is executed twice: once in rshell and once in a real bash shell, ensuring output parity with POSIX behavior. Scenarios that test rshell-specific restrictions (blocked commands, readonly enforcement, etc.) opt out of the bash comparison.
go test ./...After merging changes to main create a release by:
-
Navigate to the Releases page
-
Click "Draft a new release"
-
You can "Select a tag" using the dropdown or "Create a new tag"
When creating a new tag, make sure to include the
vprefix. For example, if the last release was v0.1.29, your release should be v0.1.30. -
The release title should be the same as the version tag
-
Use "Generate release notes" to fill in the release description
-
Click "Publish release"
This will create a git tag that can now be referenced in other repos. This will trigger go-releaser that will add installable artifacts to the release.