Checking agent actions before they run
Adding guardrails to an agent usually starts in its prompt. Something like "ask before changing anything in production" or "don't delete the things you didn't create". The agent follows those instructions most of the time, so the prompt seems to work until one day it forgets a rule.
Instructions in the prompt
The agent reads an instruction along with everything else in the conversation, and sometimes it acts against it anyway. In July 2025, a Replit agent deleted a production database during a code freeze, after being told not to make changes without approval.
Instructions can also disappear. When a long conversation is compacted, the summary can leave a rule out. In February 2026, an OpenClaw agent lost its instruction to confirm before acting this way and started deleting emails.
For simple agents, prompt instructions may be enough. As you give an agent access to more tools and data, you need a more reliable way to enforce its permissions.
Checks in agent code
Agent frameworks like LangChain, AI SDK, Mastra, and Pydantic AI all support tool approvals in agent code. You mark a tool as needing approval, and each call to it waits until someone approves or rejects it.
This works well for a single agent you manage yourself. With more agents, especially ones built by different teams, the rules become harder to keep track of. Finding an agent's permissions means reading its code, and changing a hardcoded rule requires a redeploy.
Permissions outside the agent
You can move the rules into a policy file outside the agent. Before a tool runs, the agent submits the tool name and arguments for a permission check. The policy decides whether the call can run, needs approval, or is denied.
Agents built by different teams or with different frameworks can go through the same check. You can see their permissions in the policies and change a rule without editing or redeploying the agents.
Checking the arguments
Requiring approval for a tool works well until that tool is something generic like bash. Then git status needs the same approval as terraform apply. If most commands are routine, approving each one becomes a chore.
Checking the arguments lets you allow specific commands, block others, and ask for approval for the rest.
An example policy
In Rebuno, these rules go in the agent's policy. Each tool call is recorded as a step, and the kernel checks it against the policy before it runs.
Here's a policy for an agent with a bash tool. Three commands run without asking, commands containing rm -rf are denied, and every other bash command waits for approval.
default_action: denyrules: - id: allow-safe when: target: bash arguments: command: one_of: ["git status", "git diff", "npm test"] then: decision: allow - id: no-rm-rf when: target: bash arguments: command: contains: rm -rf then: decision: deny reason: commands containing rm -rf are blocked - id: approve-other when: target: bash then: decision: require_approval reason: other commands need approval
Rules are checked in order they are written, and the first match decides. git status matches the allow-safe rule and runs right away. rm -rf data/ matches no-rm-rf and is denied. terraform apply doesn't match with the first two rules so it falls through to approve-other.
If you later decide the agent can run git log without asking, you add it to the list in allow-safe. The next git log runs without approval, with no changes to the agent's code.
To learn more about Rebuno, read the docs or visit the repository on GitHub.