AI governance for developers: approval gates, audit logs, and keeping agents in check

AI governance security lock

AI agents can now browse the web, write and execute code, send emails, query databases, and trigger API calls — all autonomously. That capability is exciting, but it creates a new class of risk that developers need to manage deliberately. AI governance is not bureaucracy for its own sake; it is the set of practices that keep autonomous systems from causing expensive, embarrassing, or irreversible mistakes.

Why governance matters for agentic AI

Traditional software does exactly what the code says. An AI agent does what the model infers you want — which is not always the same thing. The gap between intent and execution widens as agents take more steps and operate over longer time horizons. Without governance controls, a single ambiguous instruction can cascade into dozens of unintended actions before anyone notices.

The risks are concrete: an agent with write access to a production database can delete records; an agent with email access can send messages to customers; an agent with cloud credentials can spin up expensive infrastructure. Each of these has happened in real deployments.

Approval gates: human-in-the-loop by design

An approval gate is a checkpoint where an agent pauses and waits for a human to confirm before proceeding with a consequential action. The key design question is: which actions require a gate?

A practical framework classifies actions by reversibility and blast radius:

Action typeExampleGate required?
Read-onlyQuery database, fetch API dataNo
Reversible writeDraft email, create draft documentNo (review before send)
Reversible publishPost to staging environmentSoft confirmation
Irreversible actionSend email, delete record, deploy to productionHard approval required
High blast radiusBulk operations, schema changes, billing changesHard approval + escalation
# Example: approval gate pattern in Python
import asyncio
from typing import Callable, Any

async def execute_with_gate(
    action_description: str,
    action_fn: Callable,
    requires_approval: bool = False,
    *args, **kwargs
) -> Any:
    if requires_approval:
        print(f"⚠️  Approval required: {action_description}")
        confirmation = input("Proceed? (yes/no): ").strip().lower()
        if confirmation != "yes":
            raise PermissionError(f"Action blocked by user: {action_description}")
    
    result = await action_fn(*args, **kwargs)
    return result

# Usage
await execute_with_gate(
    action_description="Delete 47 records from orders table where status='cancelled'",
    action_fn=delete_cancelled_orders,
    requires_approval=True
)

Audit logs: the foundation of accountability

Every action an AI agent takes should be logged with enough detail to reconstruct what happened and why. A good audit log entry captures: timestamp, agent identity, action type, input parameters, output/result, and the reasoning or instruction that triggered the action.

// Structured audit log entry (TypeScript)
interface AgentAuditEntry {
  timestamp: string;        // ISO 8601
  agentId: string;          // which agent/session
  action: string;           // what action was taken
  parameters: object;       // inputs to the action
  result: 'success' | 'failure' | 'blocked';
  reasoning?: string;       // why the agent chose this action
  approvedBy?: string;      // who approved, if gate required
  reversible: boolean;
  metadata?: object;
}

// Example entry
const entry: AgentAuditEntry = {
  timestamp: new Date().toISOString(),
  agentId: 'billing-agent-v2',
  action: 'send_email',
  parameters: { to: 'customer@example.com', subject: 'Invoice #1042' },
  result: 'success',
  reasoning: 'Invoice generated; task requires notification to customer',
  approvedBy: 'sarah@company.com',
  reversible: false,
};

await auditLog.write(entry);

Principle of least privilege for agents

Give agents only the permissions they need for their specific task, not the permissions that would be convenient. A document summarisation agent needs read access to the document store — it does not need write access, delete access, or access to unrelated systems. This limits the blast radius of any mistake or compromise.

In practice this means creating scoped API keys and credentials per agent, rotating them regularly, and auditing access patterns. An agent that has never used a particular permission is a candidate for having that permission removed.

Rate limiting and circuit breakers

An agent running in a loop can make hundreds of API calls in seconds. Rate limiting prevents runaway agents from exhausting quotas, incurring large bills, or hammering downstream services. Circuit breakers halt an agent when error rates exceed a threshold — better to pause and alert a human than to continue a task that is clearly going wrong.

Practical checklist for teams

  • Define which actions are reversible and which are not before writing any agent code
  • Implement structured audit logging from day one — retrofitting it is painful
  • Use scoped credentials per agent, not shared admin keys
  • Set hard rate limits and alert thresholds on all external calls
  • Test what happens when the agent is given a malformed or adversarial instruction
  • Maintain a kill switch — a way to halt all agent activity immediately

The goal is not to slow down what AI agents can do — it is to build systems where mistakes are caught early, recoverable, and visible. That foundation is what allows teams to trust agents with increasingly important work over time. For more on what AI agents can do in a development workflow, see the post on agentic AI and the DevTools available at atebyteapps.com.

Leave a Reply

Your email address will not be published. Required fields are marked *