Guardrails
Guardrails let you control what the agent is allowed to do — before it does it.
think → act
↓
[guardrail gate] ← requires_approval set?
↓ ↓
allowed approval_callback()
↓ ↓
tool runs yes → runs no → skipped
The problem they solve
An LLM agent can call any tool it has access to, including destructive ones
like file_delete, shell_run, or browser_fill. Without guardrails, a
misunderstood instruction can cause irreversible damage.
Guardrails intercept tool calls before execution and either:
- Block until a human approves (approval gate)
- Cap total runtime or cost (budget limit)
- Restrict which files and commands are reachable (workspace policy)
GuardrailPolicy — approval gate
Specify which tool names must wait for human approval before running.
from gantrygraph.security import GuardrailPolicy
guardrail = GuardrailPolicy(
requires_approval={"shell_run", "file_delete"}
)
Any tool not in requires_approval runs freely — only the listed names trigger the gate.
Wire it into the engine with an approval_callback:
from gantrygraph import GantryEngine
async def ask_human(tool_name: str, args: dict) -> bool:
print(f"Allow {tool_name}({args})? [y/N] ", end="")
return input().strip().lower() == "y"
agent = GantryEngine(
llm=...,
tools=[...],
guardrail=guardrail,
approval_callback=ask_human,
)
If approval_callback returns False, the tool is skipped and the LLM receives
a "denied" message — it can then try a different approach.
BudgetPolicy — cost and time cap
Hard-stop the agent if it runs too long or exceeds a step count.
from gantrygraph.security import BudgetPolicy
agent = GantryEngine(
llm=...,
budget=BudgetPolicy(
max_steps=30,
max_wall_seconds=120.0, # raises TimeoutError after 2 minutes
),
)
Use max_wall_seconds for unattended agents so a stuck loop doesn't run forever.
WorkspacePolicy — file system isolation
Lock the agent to a directory. It cannot read, write, or execute anything outside it.
from gantrygraph.security import WorkspacePolicy
agent = GantryEngine(
llm=...,
workspace_policy=WorkspacePolicy(workspace_path="/app"),
# automatically adds FileSystemTools + ShellTools scoped to /app
)
Path traversal attempts like ../../etc/passwd are rejected before the tool runs.
Combine all three
from gantrygraph.security import GuardrailPolicy, BudgetPolicy, WorkspacePolicy
agent = GantryEngine(
llm=...,
workspace_policy=WorkspacePolicy(workspace_path="/app"),
guardrail=GuardrailPolicy(requires_approval={"shell_run", "file_delete"}),
budget=BudgetPolicy(max_steps=50, max_wall_seconds=300),
approval_callback=ask_human,
)
See also: Human approval guide · API reference