macOS note: We are currently working with Apple to obtain the Endpoint Security Framework entitlements required for full enforcement on macOS. Until then, the macOS binary has limited security capabilities (FUSE-T file monitoring only, no process or network enforcement). For production use, we recommend Linux.
Windows note: We are working to get the minifilter drivers signed. Until then, only Windows WSL2 mode is fully supported for production use.
Secure, policy-enforced execution gateway for AI agents.
agentsh sits under your agent/tooling—intercepting file, network, process, and signal activity (including subprocess trees), enforcing the policy you define, and emitting structured audit events.
Platform note: Linux provides full enforcement (100% security score). macOS supports two tiers: ESF+NE (90% score, requires Apple entitlements) for enterprise deployments, and FUSE-T (70% score) as a fallback. Windows supports native enforcement via minifilter driver with AppContainer sandbox isolation (85% score). See the Platform Comparison Matrix for details.
- Drop-in shell/exec endpoint that turns every command (and its subprocesses) into auditable events.
- Per-operation policy engine:
allow,deny,approve(human OK),soft_delete, orredirect. - Full I/O visibility:
- file open/read/write/delete
- network connect + DNS
- process start/exit
- PTY activity
- LLM API requests with DLP and usage tracking
- signal send/block (Linux enforced, macOS/Windows audit)
- Two output modes:
- human-friendly shell output
- compact JSON responses for agents/tools
Agent workflows eventually run arbitrary code (pip install, make test, python script.py). Traditional "ask for approval before running a command" controls stop at the tool boundary and can't see what happens inside that command.
agentsh enforces policy at runtime, so hidden work done by subprocesses is still governed, logged, and (when required) approved.
Most systems can deny an action. agentsh can also redirect it.
That means when an agent tries the wrong approach (or brute-force workarounds), policy can steer it to the right path by swapping the command and returning guidance—keeping the agent on the paved road and reducing wasted retries.
Example: redirect curl to an audited wrapper
command_rules: - name: redirect-curl commands: [curl, wget] decision: redirect message: "Downloads routed through audited fetch" redirect_to: command: agentsh-fetch args: ["--audit"]
Example: redirect writes outside workspace back inside
file_rules: - name: redirect-outside-writes paths: ["/home/**", "/tmp/**"] operations: [write, create] decision: redirect redirect_to: "/workspace/.scratch" message: "Writes outside workspace redirected to /workspace/.scratch"
The agent sees a successful operation (not an error), but you control where things actually land.
Containers isolate the host surface; agentsh adds in-container runtime visibility and policy.
- Per-operation audit (files, network, commands) shows what happened during installs/builds/tests.
- Approvals and rules persist across long-lived shells and subprocess trees—not just the first command.
- Path-level controls on mounted workspaces/caches/creds; containers don't natively give that granularity.
- Same behavior on host and in containers, so CI and local dev see the same policy outcomes.
From a GitHub Release
Download the .deb, .rpm, or .apk for your platform from the releases page.
# Example for Debian/Ubuntu sudo dpkg -i agentsh_<VERSION>_linux_amd64.deb
From source (Linux)
make build sudo install -m 0755 bin/agentsh bin/agentsh-shell-shim /usr/local/bin
From source (macOS)
# FUSE-T mode (standard, requires brew install fuse-t) CGO_ENABLED=1 go build -o bin/agentsh ./cmd/agentsh # ESF+NE enterprise mode (requires Xcode 15+, Apple entitlements) make build-macos-enterprise
See macOS Build Guide for detailed macOS build instructions.
# Start the server (optional if using autostart) ./bin/agentsh server --config configs/server-config.yaml # Create a session and run a command (shell output) SID=$(./bin/agentsh session create --workspace . | jq -r .id) ./bin/agentsh exec "$SID" -- ls -la # Structured output for agents ./bin/agentsh exec --output json --events summary "$SID" -- curl https://example.com
## Shell access - Run commands via agentsh, not directly in bash/zsh. - Use: `agentsh exec $SID -- <your-command-here>` - For structured output: `agentsh exec --output json --events summary $SID -- <your-command-here>` - Get session ID first: `SID=$(agentsh session create --workspace . | jq -r .id)`
You do not need to start agentsh server yourself.
- The first
agentsh exec(or any shimmed/bin/sh//bin/bash) will automatically launch a local server usingconfigs/server-config.yaml(orAGENTSH_CONFIGif set). - That server keeps the FUSE layer and policy engine alive for the session lifetime; subsequent commands reuse it.
- Set
AGENTSH_NO_AUTO=1if you want to manage the server lifecycle manually.
See Dockerfile.example for a minimal Debian-based image.
Inside the image, install a release package (or copy your build), then activate the shim:
agentsh shim install-shell \ --root / \ --shim /usr/bin/agentsh-shell-shim \ --bash \ --i-understand-this-modifies-the-host
Point the shim at your server (sidecar or host):
ENV AGENTSH_SERVER=http://127.0.0.1:18080Now any /bin/sh -c ... or /bin/bash -lc ... in the container routes through agentsh.
Recommended pattern: run agentsh as a sidecar (or PID 1) in the same pod/service and share a workspace volume; the shim ensures every shell hop stays under policy.
allowdenyapprove(human OK)redirect(swap a command)audit(allow + log)soft_delete(quarantine deletes with restore)
- file operations
- commands
- environment vars
- network (DNS/connect)
- PTY/session settings
- first matching rule wins
Rules live in a named policy; sessions choose a policy.
Defaults:
- sample config:
configs/server-config.yaml - default policy:
configs/policies/default.yaml - env override: set
AGENTSH_POLICY_NAMEto an allowed policy name (no suffix). If unset/invalid/disallowed, the default is used. - env policy: configure
policies.env_policy(allow/deny, max_bytes, max_keys, block_iteration) and per-commandenv_*overrides in policy files. Empty allowlist defaults to minimal PATH/LANG/TERM/HOME with built-in secret deny list; setblock_iterationto hide env iteration (requires env shim). - allowlist: configure
policies.allowedinconfig.yml; empty means only the default is permitted. - optional integrity: set
policies.manifest_pathto a SHA256 manifest to verify policy files at load time.
- Defaults: With no
env_allow, agentsh builds a minimal env (PATH/LANG/TERM/HOME) and strips built-in secret keys. - Overrides: Per-command
env_allow/env_denyplusenv_max_keys/env_max_bytescap and filter the child env at exec time. - Block iteration:
env_block_iteration: true(global or per rule) hides env enumeration; setpolicies.env_shim_pathtolibenvshim.soso agentsh injectsLD_PRELOAD+AGENTSH_ENV_BLOCK_ITERATION=1. - Limits: Errors if limits are exceeded; env builder is applied before exec for every command.
- env_inject: Operator-trusted environment variables injected into all commands, bypassing policy filtering. Primary use:
BASH_ENVto disable shell builtins that bypass seccomp. Configure insandbox.env_inject(global) or policy-levelenv_inject(overrides global). - Examples: See
config.ymland policy samples underconfigs/.
version: 1 name: default file_rules: - name: allow-workspace paths: ["/workspace", "/workspace/**"] operations: [read, open, stat, list, write, create, mkdir, chmod, rename] decision: allow - name: approve-workspace-delete paths: ["/workspace", "/workspace/**"] operations: [delete, rmdir] decision: approve message: "Delete {{.Path}}?" timeout: 5m - name: deny-ssh-keys paths: ["/home/**/.ssh/**", "/root/.ssh/**"] operations: ["*"] decision: deny network_rules: - name: allow-api domains: ["api.example.com"] ports: [443] decision: allow command_rules: - name: block-dangerous commands: ["rm", "shutdown", "reboot"] decision: deny
# Start the server with your policy ./bin/agentsh server --config configs/server-config.yaml # Create a session pinned to a policy SID=$(./bin/agentsh session create --workspace /workspace --policy default | jq -r .id) # Exec commands; responses include decision + guidance when blocked/approved ./bin/agentsh exec "$SID" -- rm -rf /workspace/tmp
agentsh supports multiple authentication methods:
| Type | Use Case |
|---|---|
api_key |
Simple deployments with static keys |
oidc |
Enterprise SSO (Okta, Azure AD, etc.) |
hybrid |
Both methods accepted |
Approval modes for human-in-the-loop verification:
local_tty- Terminal prompt (default)totp- Authenticator app codeswebauthn- Hardware security keys (YubiKey)api- Remote approval via REST
See SECURITY.md for configuration details.
- Tool Whitelisting: Control which MCP tools can be invoked via allowlist/denylist policies
- Version Pinning: Detect tool definition changes (rug pull protection) with configurable responses
- Cross-Server Detection: Block data exfiltration patterns (read from Server A → send via Server B)
- Rate Limiting: Token bucket rate limiting for MCP servers and network domains
See SECURITY.md for full configuration options, or run the MCP Protection Demo to see these detections in action.
The fastest way to "get it" is to run something that spawns subprocesses and touches the filesystem/network.
# 1) Create a session in your repo/workspace SID=$(agentsh session create --workspace . | jq -r .id) # 2) Run something simple (human-friendly output) agentsh exec "$SID" -- uname -a # → prints system info, just like normal # 3) Run something that hits the network (JSON output + event summary) agentsh exec --output json --events summary "$SID" -- curl -s https://example.com # → JSON response includes: exit_code, stdout, and events[] showing dns_query + net_connect # 4) Trigger a policy decision - try to delete something agentsh exec "$SID" -- rm -rf ./tmp # → With default policy: prompts for approval or denies based on your rules # 5) See what happened (structured audit trail) agentsh exec --output json --events all "$SID" -- ls # → events[] shows every file operation, even from subprocesses
What you'll see in the JSON output:
exit_code: the command's exit statusstdout/stderr: captured outputevents[]: every file/network/process operation with policy decisionspolicy.decision:allow,deny,approve, orredirect
Tip: keep a terminal with --output json open when testing policies—it makes it obvious what's being touched.
Generate markdown reports summarizing session activity:
# Quick summary agentsh report latest --level=summary # Detailed investigation agentsh report <session-id> --level=detailed --output=report.md
Reports include:
- Decision summary (allowed, blocked, redirected)
- Automatic findings detection (violations, anomalies)
- Activity breakdown by category
- Full event timeline (detailed mode)
See CI/CD Integration Guide for pipeline examples.
Create snapshots of workspace state for recovery from destructive operations:
# Create a checkpoint before risky operations agentsh checkpoint create --session $SID --workspace /workspace --reason "before cleanup" # List checkpoints for a session agentsh checkpoint list --session $SID # Show what changed since a checkpoint agentsh checkpoint show <cp-id> --session $SID --workspace /workspace --diff # Preview what rollback would restore (dry-run) agentsh checkpoint rollback <cp-id> --session $SID --workspace /workspace --dry-run # Restore workspace to checkpoint state agentsh checkpoint rollback <cp-id> --session $SID --workspace /workspace # Clean up old checkpoints agentsh checkpoint purge --session $SID --older-than 24h --keep 5
Auto-checkpoint: When enabled, agentsh automatically creates checkpoints before risky commands (rm, mv, git reset, git checkout, etc.). Configure in sessions.checkpoints.auto_checkpoint.
See SECURITY.md for full configuration options.
agentsh includes an embedded proxy that intercepts all LLM API requests from agents:
# Check proxy status for a session agentsh proxy status <session-id> # View LLM-specific events agentsh session logs <session-id> --type=llm
Features:
- Automatic routing: Sets
ANTHROPIC_BASE_URLandOPENAI_BASE_URLso agent SDKs route through the proxy - Custom providers: Route to LiteLLM, Azure OpenAI, vLLM, or corporate gateways
- DLP redaction: PII (emails, phone numbers, API keys, etc.) is redacted before reaching LLM providers
- Custom patterns: Define organization-specific patterns for sensitive data
- Usage tracking: Token counts extracted and logged for cost attribution
- Audit trail: All requests/responses logged to session storage
Provider configuration:
proxy: mode: embedded providers: anthropic: https://api.anthropic.com # Default Anthropic API openai: https://api.openai.com # Default OpenAI API # Or use alternative providers: # openai: http://localhost:8000 # LiteLLM / vLLM # openai: https://your-resource.openai.azure.com # Azure OpenAI # anthropic: https://llm.corp.example.com # Corporate gateway
DLP configuration:
dlp: mode: redact patterns: email: true api_keys: true custom_patterns: - name: customer_id display: identifier regex: "CUST-[0-9]{8}"
See LLM Proxy Documentation for full configuration options.
Generate restrictive policies from observed session behavior ("profile-then-lock" workflow):
# Generate policy from latest session agentsh policy generate latest --output=ci-policy.yaml # Generate with custom name and threshold agentsh policy generate abc123 --name=production-build --threshold=10 # Quick preview to stdout agentsh policy generate latest
The generated policy:
- Allows only operations observed during the session
- Groups paths into globs when many files in same directory
- Collapses subdomains into wildcards (e.g.,
*.github.com) - Flags risky commands (curl, wget, rm) with arg patterns
- Includes blocked operations as commented-out rules for review
Use cases:
- CI/CD lockdown: Profile a build/test run, lock future runs to that behavior
- Agent sandboxing: Let an AI agent run a task, generate policy for future runs
- Container profiling: Profile a workload, generate minimal policy for production
agentsh can transparently redirect DNS and TCP connections, enabling use cases like routing API calls through corporate proxies or switching AI providers without code changes.
Intercept DNS resolution and return configured IP addresses:
dns_redirect: - match: "api.anthropic.com" redirect_ip: "10.0.0.50" visibility: audit_only on_failure: fail_closed - match: ".*\\.openai\\.com" # Regex pattern redirect_ip: "10.0.0.51" visibility: warn
Redirect TCP connections to different destinations with optional TLS handling:
connect_redirect: - match: "api.anthropic.com:443" redirect_to: "vertex-proxy.internal:8443" tls_mode: passthrough # Forward encrypted traffic unchanged visibility: silent - match: "api.openai.com:443" redirect_to: "azure-proxy.internal:443" tls_mode: rewrite_sni # Modify SNI in TLS ClientHello rewrite_sni: "azure-openai.example.com" visibility: audit_only
| Field | Values | Description |
|---|---|---|
visibility |
silent, audit_only, warn |
How redirects are logged/shown |
on_failure |
fail_closed, fail_open, retry_original |
What happens if redirect fails |
tls_mode |
passthrough, rewrite_sni |
TLS handling for connect redirect |
| Feature | Linux | macOS | Windows |
|---|---|---|---|
| DNS Redirect | ✅ eBPF | ✅ pf/proxy | ✅ WinDivert |
| Connect Redirect | ✅ eBPF | ✅ pf/proxy | ✅ WinDivert |
| SNI Rewrite | ✅ | ✅ | ✅ |
- API Gateway Routing: Route Anthropic/OpenAI calls through corporate LLM gateway
- Provider Switching: Redirect Claude API to GCP Vertex AI or Azure OpenAI
- Testing: Redirect production APIs to mock servers
- Compliance: Force all LLM traffic through audit proxies
agentsh intercepts signals (kill, SIGTERM, etc.) sent between processes, providing policy-based control over which signals can reach which targets.
| Platform | Blocking | Redirect | Audit |
|---|---|---|---|
| Linux | Yes (seccomp user-notify) | Yes | Yes |
| macOS | No | No | Yes (ES) |
| Windows | Partial | No | Yes (ETW) |
signal_rules: # Allow signals to self and children - name: allow-self signals: ["@all"] target: type: self decision: allow - name: allow-children signals: ["@all"] target: type: children decision: allow # Redirect SIGKILL to graceful SIGTERM - name: graceful-kill signals: ["SIGKILL"] target: type: children decision: redirect redirect_to: SIGTERM # Block fatal signals to external processes - name: deny-external-fatal signals: ["@fatal"] target: type: external decision: deny
@all- All signals (1-31)@fatal- SIGKILL, SIGTERM, SIGQUIT, SIGABRT@job- SIGSTOP, SIGCONT, SIGTSTP, SIGTTIN, SIGTTOU@reload- SIGHUP, SIGUSR1, SIGUSR2
self- Process signaling itselfchildren- Direct child processesdescendants- All descendant processessession- Any process in the agentsh sessionexternal- PIDs outside the sessionsystem- PID 1 and kernel threads
See Policy Documentation for full configuration options.
You already have a default policy (configs/policies/default.yaml). These opinionated packs are available as separate files so teams can pick one:
-
policies/dev-safe.yaml: safe for local development- allow workspace read/write
- approve deletes in workspace
- deny
~/.ssh/**,/root/.ssh/** - restrict network to allowlisted domains/ports
-
policies/ci-strict.yaml: safe for CI runners- deny anything outside workspace
- deny outbound network except artifact registries
- deny interactive shells unless explicitly allowed
- audit everything (summary events)
-
policies/agent-sandbox.yaml: "agent runs unknown code" mode- default deny + explicit allowlist
- approve any credential/path access
- redirect network tool usage to internal proxies/mirrors
- soft-delete destructive operations for easy recovery
Ready-to-use snippets for configuring AI coding assistants to use agentsh:
- Claude Code - CLAUDE.md snippet for Claude Code integration
- Cursor - Cursor rules for agentsh integration
- AGENTS.md - Generic AGENTS.md snippet (works with multiple AI tools)
Note: These examples are for local development scenarios where running the AI agent inside a container isn't practical. For production or CI/CD environments, prefer running agents in containers with the shell shim installed—see Use in Docker.
- MCP Protection Demo:
agentsh-mcp-protection-demo- live demo of cross-server exfiltration detection, rug pull blocking, and policy generation - Security & threat model:
SECURITY.md- what agentsh protects against, known limitations, operator checklist - External KMS:
SECURITY.md#external-kms-integration- AWS KMS, Azure Key Vault, HashiCorp Vault, GCP Cloud KMS for audit integrity keys - Config template:
configs/server-config.yaml - Default policy:
configs/policies/default.yaml - Example Dockerfile (with shim):
Dockerfile.example - Policy documentation:
docs/operations/policies.md- policy variables, signal rules, network redirect - Platform comparison:
docs/platform-comparison.md- feature support, security scores, performance by platform - Bubblewrap vs agentsh:
docs/bubblewrap-vs-agentsh-comparison.md- comparison with Bubblewrap for Linux container sandboxing - LLM Proxy & DLP:
docs/llm-proxy.md- embedded proxy configuration, DLP patterns, usage tracking - macOS build guide:
docs/macos-build.md- FUSE-T and ESF+NE build instructions - macOS ESF+NE architecture:
docs/macos-esf-ne-architecture.md- System Extension, XPC, and deployment details - macOS XPC sandbox:
docs/macos-xpc-sandbox.md- XPC/Mach IPC control for sandboxed processes - Environment variables (all
AGENTSH_*overrides, auto-start toggles, transport selection):docs/spec.md§15.3 "Environment Variables" - Architecture & data flow (FUSE + policy engine + API): inline comments in
configs/server-config.yamlandinternal/netmonitor - CLI help:
agentsh --help,agentsh exec --help,agentsh shim --help
Created with the help of agents for agents.