Home › Blog › The bash allowlist: safe-by-default shell execution for agents
Blog

The bash allowlist: safe-by-default shell execution for agents

Jul 19, 20265 min readBy the Rysh team

Approve everything and you'll rubber-stamp. Approve nothing and the agent is useless. Rysh's answer: an allowlist where unknown means ask.

Give an agent a shell and you've made a choice, whether you admit it or not.

Option one: it asks permission for every command. By day two you're hammering "approve" on ls without reading it — and the day it slips rm -rf into the queue, your reflexes approve that too. Blanket prompting doesn't produce safety; it produces rubber-stamp fatigue.

Option two: it asks for nothing. Fast, fun, and you've handed root-adjacent power to a stochastic process. Everyone has read at least one postmortem that starts this way.

Rysh picks a third option, and it's the boring, correct one from decades of security engineering: an allowlist, with safe-by-default fallthrough.

The policy in one paragraph

When a rysh agent calls the bash tool, the command is classified before it runs. Commands on a short allowlist of reads, builds and tests execute freely — no prompt, no friction. Everything not on the list asks you first. And "everything else" explicitly includes the command the classifier doesn't recognize: unknown means ask, never "probably fine."

What runs free

The allowlist is built around the commands an engineer runs a hundred times a day to look at the world without changing it:

Notice what these have in common: run them once or run them fifty times, the world is the same afterwards. That's the property the allowlist aims at — not "commands we like," but idempotence and read-only-ness. It matches by prefix, though, so a few listed commands have writing forms that also run free: git branch -D, git remote remove, gofmt -w, golangci-lint run --fix. Still, it's why an agent in rysh can investigate a bug at full speed: grep the codebase, walk the git history, run the tests, list the processes — zero prompts.

(Yes, go test can technically mutate things if your tests are badly behaved. The allowlist encodes the contract that tests are hermetic; if yours aren't, that's worth fixing for reasons well beyond rysh.)

What gets stopped at the gate

The RequiresApproval check on rysh's bash tool flags the shapes that change the world or smuggle in something that could:

When one of these comes up, you get a pre-approval prompt: the command, and a decision that's rare enough to actually think about. That's the payoff of the allowlist — by letting the routine reads flow, the prompts that do reach you deserve and get your attention.

One more deliberate wrinkle: git commit never runs free in bash. It has a dedicated, always-gated tool (git_commit), because writing to your repo history is a decision with your name on it. Reads are bash; commits are ceremony.

Why shape-based classification beats vibes

A tempting alternative is to let the model itself judge "is this command safe?" Don't. The model is the thing being governed; it can't also be the governor. Rysh's classification is structural — it looks at what the command is (read vs mutate, redirect vs not, substitution vs not), not at how confidently anyone describes it.

Structural rules are auditable. You can read the policy and predict, for any command, whether it will prompt. No surprises in either direction — and no prompt-injection path where a cleverly-worded task convinces anyone that curl | sh is "just reading."

This layers with the rest of rysh's governance rather than standing alone: file edits are preview-first (you see the diff before disk changes), every tool call is visible in the pane as it happens, and secrets the detectors recognise are swapped for tokens before a request leaves your machine. The allowlist is one gate in a fence, not the fence.

The trust curve this buys you

Here's what actually happens on teams that adopt agents: trust isn't granted, it's accumulated. Day one, you read every prompt. Week two, you've watched the agent's mutating commands be sensible fifty times, and each approval takes two seconds. The gate doesn't disappear unless you switch it off (a policy rule, a "yes, always", or a headless agent run) — but it stops being friction and becomes a heartbeat: proof that you're still the one holding the pen for anything off the list.

That's the honest pitch. Not "our agent never makes mistakes" — it runs on Claude (your API key, your machine), and no model is infallible. The pitch is: the commands an agent can run without you are the ones on a list you can read. Everything else has your fingerprint on it.

Safe by default. Fast where it's free. Loud where it counts.


This is the governance layer teams keep telling us they were missing. Help us shape it — become a design partner: rysh.ai/design-partner.

More in this series: Preview-first editing: coloured diffs before anything touches disk · Is it safe to let an agent loose on your systems? An honest checklist

Try Rysh

Every pane is a shell and an AI agent — install takes one command.

Get started free →