Agents can be tricked, jailbroken, or simply wrong. agentsh enforces what they can do at runtime—no matter what the prompt, tool output, or user says.
Enforce at the system boundary. Prompts are advisory; syscalls are real. agentsh evaluates every file/network/process action and applies your policy before it happens.
Why agentsh
Prompt injection, jailbreaks, and plain old mistakes all look the same at the OS boundary. agentsh intercepts runtime actions and enforces your rules—allow, deny, approve, or redirect—with a complete audit trail.
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
## 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:8080 # 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 redirected, 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 redirect:
Redirect 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.
command_rules:
# Route downloads through audited proxy
- name: redirect-curl
commands: [curl, wget]
decision: redirect
message: "Downloads routed through audit"
redirect_to:
command: agentsh-fetch
args: ["--audit"]
file_rules:
# Agent tries /tmp? Fine, but it lands in workspace
- name: redirect-outside-writes
paths: ["/tmp/**", "/var/**", "/home/**"]
operations: [write, create]
decision: redirect
redirect_to: "/workspace/.scratch"
message: "Writes redirected to workspace"
# Trying to read secrets? Get a placeholder instead
- name: redirect-secrets
paths: ["**/.env", "**/*secret*", "**/*credential*"]
operations: [read]
decision: redirect
redirect_to: "/workspace/.mock-secrets"
message: "Secret access redirected to mock"
Open source. Practical by default. Built for real agent runs—where mistakes are expensive.
Need centralized policy, approvals, kill-switches, and SIEM hooks?
Explore Enterprise