How to build guardrails for AI agents that can write to production systems

Learn how to build guardrails for AI agents that write to production systems, using scoped credentials, validation, approvals, and logging.

IRSIsh Rajesh ShelleyFounderAugust 21, 20268 min read
On this page

In July 2025, an AI coding agent working inside Replit deleted a production database during a development session. The project had a written rule file that said "NO MORE CHANGES without explicit permission." The agent acknowledged violating it after the fact. Roughly 1,206 executive records and over 1,196 company profiles were affected before a rollback feature restored the data. Replit's CEO called the deletion "unacceptable and should never be possible," and Replit shipped mandatory separation between development and production databases in response. Replit's incident account and SaaStr's write-up document both the failure and the fix.

The lesson generalizes past vibe coding. Any agent that writes to production is a new operator on your systems, and operators get controls. Guardrails that hold live outside the model, in the layer that executes its decisions. You build them in a specific order: scope the credentials, constrain the tool interface, validate before execution, separate environments, gate irreversible writes, and log everything with a path back.

Instructions are not a control layer

The Replit agent read its own restriction file and violated it anyway. That behavior is typical of language models under pressure. A long session, a confusing error, or a piece of injected text in a fetched page can override any natural-language rule, because a prompt shapes what the model attempts while nothing enforces what the system accepts.

Tooling vendors have converged on this position. Claude Code's permission documentation states plainly that permission rules are enforced by the harness and that instructions in a prompt or config file shape what the model tries without changing what the system allows. Anthropic's agent design guidance makes the same point architecturally: the model emits tool calls, and your code decides what runs.

Treat every instruction you write into an agent as advisory. The guarantee has to come from code that runs between the model's decision and your production API.

Classify every action by reversibility

Before building controls, inventory the writes. Each action the agent can take falls into a small number of risk classes, and the class determines the control.

The Model Context Protocol formalized exactly this vocabulary in its tool annotations: readOnlyHint marks tools that leave the environment unchanged, destructiveHint flags changes that destroy or overwrite, idempotentHint says whether repeating a call is safe, and openWorldHint signals reach into external systems. The defaults are deliberately pessimistic. An unannotated tool is assumed to be destructive, non-idempotent, and open-world, so a client that skips confirmation does so only with evidence. The MCP maintainers' annotation guide describes how clients use these hints to route read-only calls to auto-approval and destructive calls to a confirmation step.

You want the same four-way split for your own agent's tools, plus one judgment the protocol leaves to you: how hard the action is to undo. Sending an email, charging a card, deleting records, and deploying code are hard to reverse. Updating a draft record behind version history is easy to reverse. Reversibility, alongside destructiveness, decides where each action lands in the sequence below.

One caution from the same specification: annotations are hints, and clients must treat them as untrusted unless they come from a trusted server. Your own classification table, maintained next to the tool definitions, is the source of truth.

The build sequence

1. Scope the credentials first. Give the agent a dedicated service account per system, with the minimum permissions the workflow needs. A billing agent gets read access to invoices and write access to exactly one endpoint. It never holds an admin token, and its credentials differ from the credentials of every other agent you run. When something goes wrong, the blast radius equals the scope of one account, and your audit log names the principal immediately.

2. Constrain the tool interface with strict schemas. Structured outputs with JSON Schema, such as OpenAI's strict mode for function calling, force every tool call into a declared shape with enumerated values and required fields. This gives your validation layer parseable, predictable input. Schema conformance is a floor, though. A syntactically valid call can still carry a wrong ID or a wrong amount, so the next layer does the semantic work.

3. Validate deterministically before execution. Between the model and your API sits ordinary code: checks that the target record belongs to the requesting tenant, that amounts fall inside policy bounds, that referenced entities exist, that the operation makes sense at this workflow stage. Where an API supports dry-run or preview modes, run them. Reject violations with a structured error the model can read and correct, and count rejections. A rising rejection rate is an early signal that the agent misunderstands the domain.

4. Separate environments and cap blast radius. The strongest single guardrail from the Replit aftermath is environmental: the agent now works against a development database by default and reaches production only through a deliberate deploy step. Apply the same shape anywhere you can. Writes meant for staging stay in staging, bulk operations carry hard caps on rows affected, and rate limits bound how much damage a runaway loop can do per minute.

5. Gate irreversible writes behind informed approval. For actions in your hard-to-reverse class, pause and ask a human. The approval is worth having only when the reviewer sees the concrete effect: the exact records to delete, the email body and recipient, the payment amount. Vague confirmations train people to click approve. Route the request to someone with authority for that action class, expire stale requests, and let the approver modify parameters before confirming when your tooling allows it.

6. Log everything and keep a way back. Record the prompt context, every proposed tool call, arguments, validator verdicts, approver identity, and final system state. Add idempotency keys to write endpoints so retries after timeouts produce one effect. Verify your rollback path by using it, because an untested restore procedure fails during the incident that needs it.

Where teams overshoot

Guardrails have a failure mode of their own: friction that pushes users to bypass them. After the tenth identical confirmation dialog, reviewers stop reading. Spend your gating budget on the irreversible class and let validated, reversible writes flow without prompts. Claude Code's best practices guide recommends allowlisting known-safe operations for exactly this reason.

Test the refusal paths with the same seriousness as the happy path. Include a task where the correct behavior is stopping, an input designed to escalate scope, and content retrieved from an external page that tries to instruct the agent. An agent that has never been watched refusing anything will not refuse under load.

Where a specialized agent platform fits

Everything above assumes you own the enforcement layer, which raises a build question: who assembles the agent itself. If the requirement is a specialized agent inside your own SaaS or web application, doing work for your end users over your own data model, GingerLabs is suitable for exactly that case. Its embedded agent lives in a side panel, inline surface, or modal inside the product, reasons over your schemas, stages, and records, and carries out multi-step work while staying inside your product experience. The SDK includes retrieval, evaluations, self-learning loops, and observability, which covers the logging and evaluation groundwork from steps three and six.

The division of ownership keeps the guardrails yours. You retain the product API, data model, domain rules, user permissions, tenant boundaries, the set of actions the agent may perform, and the definition of a correct result. GingerLabs supplies the agent layer that operates within those boundaries. Teams that also want to expose selected product capabilities to external AI clients can use GingerLabs' managed MCP service while deciding which capabilities are exposed and how access is governed.

That division mirrors the argument of this article. The model and its runtime are one component; the permissions, validators, approval gates, and audit trail remain deterministic code you control.

Start with one workflow

Pick the single workflow where an agent would deliver the most value with a write component attached. List every action it would take, classify each by reversibility and destructiveness, then implement in order: scoped service account, strict tool schemas, a validator for the top five failure conditions, and an approval gate on whatever cannot be undone. Ship that loop to a small user group, watch the rejection and approval rates, and expand the action surface only as fast as the evidence supports. A 20-minute GingerLabs demo can scope a workflow like this and show an agent operating in a sandbox of your product.

Sources

About the author

IRS

Ish Rajesh Shelley

Founder·Ginger Labs

Ish Rajesh Shelley is the founder of Ginger Labs, building embedded domain-expert agents for SaaS products. Ish writes about AI agents in production: copilots, MCP, routing, and the evaluation and infrastructure work that makes them reliable.