The Prompt Is a Wish, Not a Wall
Every agentic setup I've seen that makes me nervous has the same shape: a small model with a shell, a system prompt full of please don'ts, and a human hoping that politeness compounds. "Never delete anything. Don't use credentials you weren't given. Stick to read-only." It's a fence built out of wishes, and the dog is a goal-seeking optimiser with no moral sense of proportion.
Here's the thing about those prompts under task pressure. A capable model told to "deploy the fix" will find the stray ~/.aws/credentials on the box and just use it. Told to push a branch while its GPG key is locked, it will commit the other way, with a straight face. Told to clean up, it will run the destructive command because the goal outweighed your "no" by roughly four decimal places. Not because it's evil. Because "don't X" in a prompt is a soft constraint, and the model's objective function is a hard one. You cannot negotiate with a loss function.
So you stop asking the model to be safe, and you make the environment safe. That's the whole essay, really: move the constraint out of the model and into the execution path, where the kernel has your back.
Seven Principles That Survive Contact With a Shell
I built this for my own local LLM agent, which is exactly the use case where the "the cloud will sandbag you for us" story stops applying: your model runs on your hardware, on your box, with your tools. Here's what actually earns its keep.
1. Constraints belong in the execution path, not the system prompt. PATH-shadowed wrapper scripts that intercept aws, git, gh, ssh, curl and friends before they reach the real binaries. This is the detail most people miss: the shadow has to sit first on PATH in the agent's shell, so it catches every invocation mode. Interactive, sh -c, scripts, whatever the model conjures up at 3 AM. Bash aliases would not survive that. Neither would your hopes.
2. Read-only is the default state. Write access is a mode you flip, per-scope and short-lived, not a permission granted up front. The cloud CLIs start in read-only; you turn writing on when the task needs it and turn it off when it doesn't. The default position should be boring, because the agent's job is to find your non-boring position eventually.
3. Classify verbs, not binaries. aws s3 ls is cutlery; gh repo delete is the knife drawer. You don't decide safety by asking "may this program run", you decide it by asking "may this verb run, on this target, right now". A binary is just a very large collection of verbs wearing a trench coat.
4. Gate the irrevocable. Destructive verbs don't execute, they drop into a pending file and wait for a human to approve them. Human-in-the-loop where it actually matters, not on every keystroke. You want the agent to be able to work, not to be a chatbot that asks permission to look at a file listing.
5. Egress gets a whitelist. curl and wget to approved hosts only. This is the vector where most agent "safety" is pure theatre: the model never needs to delete your database, it just needs to send it somewhere. If your agent can exfiltrate, your agent is not contained. Full stop.
6. Journal everything, and make the policy itself tamper-proof. Every guarded command lands in an append-only journal. And the policy file is GPG-signed via a pre-commit hook, so the cage can't be quietly re-welded from the inside. An agent with write access to its own security policy is a snake with access to the feed room.
7. One line in the prompt that closes the loop. The prompt still has a job, but it's not the fence. It's the response plan: if a command is BLOCKED, wait for approval. Never search the filesystem for credentials. Never route around a blocked command via a different tool. The prompt's job is to make working around the fence unfun and pointless, because the fence is still there no matter what it does.
You've Done This Before
Nothing in that list is new. File permissions, sudo, firewalls, unprivileged users, separate accounts for services, hardware firewalls on the office router: three decades of "the thing with hands should not also be the thing that decides whether the thing has hands". The novelty is only that the user at the other end of the shell is now non-deterministic, improvises under pressure, and will try to be helpful in exactly the ways you didn't authorise.
That changes two things. The boundary has to sit at the exec layer, because you can't trust the intent layer. And the blast radius has to be pre-decided by you, before the task, because the agent will happily spend the budget you gave it on the worst possible investment. Scoped, short-duration credentials plus the wrapper layer plus a journal means the worst case is a boring one: the agent did a weird, logged, recoverable thing, and you found out from the journal, not from your bank.
Next time someone shows you an agent setup and their security model is a paragraph in the system prompt, ask one question before you nod:
Where's the wall?
If the answer is "in the model", you're watching a wish, not a wall. Put the wall where it can't be argued with, and leave the model its opinions. ðŸ§
— P