Policy-enforced execution gateway that intercepts file, network, and process activity at runtime—no matter what the prompt, tool output, or user says.
Models are probabilistic. Execution must be deterministic. agentsh enforces policy at the syscall level.
Why agentsh
Prompt injection, jailbreaks, and plain old mistakes all look the same at the execution layer. agentsh evaluates every action at the moment it happens—allow, deny, approve, or steer—independent of prompt compliance.
Prompts can drift. Policies don’t. Enforcement happens at the system call level—where files open, sockets connect, and processes spawn.
Every file, network, and process operation is captured—including subprocess trees—so you can understand what really happened.
Risky operations pause for explicit confirmation. Agents can request, but humans (or CI policy) decide.
Architecture
Place agentsh under your agent or harness. It intercepts syscalls, applies your policy, and emits structured events you can route anywhere.
Quick Start
# Download from GitHub releases sudo dpkg -i agentsh_<VERSION>_linux_amd64.deb # Or build from source make build sudo install -m 0755 bin/agentsh /usr/local/bin
# Create a session SID=$(agentsh session create --workspace . | jq -r .id) # Run commands through agentsh agentsh exec "$SID" -- ls -la # Structured output for agents agentsh exec --output json "$SID" -- curl https://example.com
The best way to use agentsh in development is to run your coding agent as a child process. All shell commands the agent spawns will be intercepted and policy-checked automatically.
# Claude Code agentsh exec --root . -- claude # OpenAI Codex CLI agentsh exec --root . -- codex # Cursor agentsh exec --root . -- cursor # Any agent that spawns shell commands agentsh exec --root . -- your-agent-command
## Shell access - Run commands via agentsh (not directly in bash/zsh). - Use: agentsh exec $SID -- <your-command> - For structured output: agentsh exec --output json $SID -- <cmd> - Get session ID first: SID=$(agentsh session create --workspace . | jq -r .id)
Containers limit where an agent can cause damage—but inside the container, it's still a free-for-all. The agent can read any file, access your env vars and secrets, hit any endpoint, and delete your workspace. agentsh adds the missing layer: control over what the agent can actually do.
Install a lightweight shell shim in your container.
The agent thinks it's calling /bin/bash—but every command routes through agentsh and gets policy-checked.
FROM debian:bookworm-slim # Install agentsh RUN dpkg -i agentsh_*_linux_amd64.deb # Install the shell shim — this is the magic RUN agentsh shim install-shell \ --root / \ --shim /usr/bin/agentsh-shell-shim \ --bash \ --i-understand-this-modifies-the-host # Point to agentsh server (sidecar or host) ENV AGENTSH_SERVER=http://127.0.0.1:18080 # Now any /bin/bash or /bin/sh call goes through agentsh # Agents never know the difference
/bin/bash and /bin/sh.
When an agent calls subprocess.run(["bash", "-c", "…"]), it actually hits agentsh—which applies policy and logs the outcome.
Harnesses like Claude Code or Cursor include built-in tools that bypass the shell—file edits, execution, and network requests. Run the harness itself under agentsh to govern everything end-to-end.
The gotcha: When a harness writes a file via an internal tool (e.g., str_replace),
no shell is spawned. If you only shimmed bash, you’d miss it.
# Create a session for the entire agent run SID=$(agentsh session create \ --workspace /project \ --policy agent-sandbox | jq -r .id) # Run your agent harness UNDER agentsh agentsh exec "$SID" -- claude-code --project /project # Or with Cursor, Aider, custom harness... agentsh exec "$SID" -- cursor --folder /project agentsh exec "$SID" -- python my_agent.py
# Even built-in harness tools are governed: ├─ file_write → /project/src/main.py ✓ allow ├─ file_read → /etc/passwd ✗ deny ├─ net_connect → api.openai.com:443 ✓ allow ├─ net_connect → evil.com:443 ✗ deny ├─ exec → npm install ✓ allow │ └─ file_write → /project/node_modules ✓ allow │ └─ net_connect → registry.npmjs.org ✓ allow ├─ exec → curl http://attacker.com ✗ deny └─ file_delete → /project/.env ? approve
Policy Engine
Define what's allowed, what needs approval, what gets steered, and what's blocked—using simple YAML you can version, review, and ship.
file_rules: - name: allow-workspace paths: ["/workspace/**"] operations: [read, write, create] decision: allow - name: approve-delete paths: ["/workspace/**"] operations: [delete] decision: approve message: "Delete {{.Path}}?" - name: deny-secrets paths: ["**/.env", "**/.env.*", "**/credentials*"] decision: deny - name: deny-ssh paths: ["~/.ssh/**"] decision: deny network_rules: - name: allow-api domains: ["api.example.com"] ports: [443] decision: allow command_rules: - name: block-env-dump commands: [env, printenv] decision: deny - name: block-dangerous commands: [rm, shutdown, reboot] decision: deny env_rules: - name: npm-registry-only commands: [npm, yarn] allow: [NPM_TOKEN, NODE_ENV] - name: db-migrate-only commands: [prisma, drizzle] allow: [DATABASE_URL]
Great default for local work. Workspace access, env/secrets/SSH denied, and a tight network allowlist.
Designed for CI runners. Deny outside workspace and restrict network to registries and required endpoints.
For running unknown code. Default deny, explicit allowlists, approvals, and soft-delete quarantine.
A deny often triggers “try harder.”
Different flags, different paths, Base64 encoding, creative workarounds.
You’ve seen it: dozens of retries, wasted tokens, and the task still doesn’t complete.
The deny spiral:
With steering:
Steering keeps work moving. The agent sees success and proceeds. You decide where writes land, which endpoints get hit, and what command is truly executed—without breaking the flow.
network_rules: # Route npm to internal registry - name: steer-npm destinations: ["registry.npmjs.org"] decision: redirect redirect_to: "npm.internal.corp" message: "Steered to internal registry" command_rules: # Route downloads through audited proxy - name: steer-curl commands: [curl, wget] decision: redirect message: "Downloads routed through audit" redirect_to: command: agentsh-fetch args: ["--audit"] # Low-level network steering (DNS/TCP) dns_redirects: - name: api-to-proxy match: ".*\\.anthropic\\.com" resolve_to: "10.0.0.50" connect_redirects: - name: route-api match: "api\\.anthropic\\.com:443" redirect_to: "vertex-proxy:443"
Open source. Practical by default. Built for real agent runs—where mistakes are expensive.
Need Execution-Layer Security for desktop AI tools too? Beacon monitors supervised copilots on endpoints. Watchtower provides the central control plane for both.
Explore Beacon + Watchtower