Back to Explore
GuideVibeFix 编辑部Updated Oct 14, 2026

Don't Let the Agent Drop the Database: Human-in-the-Loop Approval Flows for High-Risk Operations in Vibe Projects

The more autonomous the agent, the larger the blast radius. A "human nods before it runs" gate on deletions, refunds, broadcasts, and permission changes is the cheapest insurance. This guide gives you a risk×reversibility quadrant, a minimal ticket schema, deny-by-default timeouts, audit trails, and an emergency lane — shippable in a weekend.

Approval state machine and sequence diagram: pending approval branches to approved, rejected or timed out, all ending at audited

Why an agent's "blast radius" needs a gate

The biggest difference between a vibe project and a traditional one isn't who writes the code — it's who initiates execution. In traditional workflows, a human always stands in front of destructive operations like dropping a database, issuing refunds, or broadcasting messages: a human pressed enter, and a human was the final check. In agent workflows, the initiator is a program that "reads 10 files a minute, never mistypes, and never hesitates": it might DROP TABLE users because it misunderstood one sentence of requirements, send 2,000 apology emails because it hallucinated a user ID, or disable a paid feature because it confused staging config with production. None of this is "AI misbehaving" — it's "AI being too capable." Every point of autonomy gained is a point of blast radius gained.

Putting a "human nods before it runs" gate in front of high-risk operations is the cheapest insurance available: no agent rewrite, no enterprise IAM purchase — one ticket data structure plus one state machine and you're running. Note the distinction from our site's "three-layer content moderation funnel" guide: that one governs UGC content (what users posted); this one governs agent execution (what the agent is about to do) — different subjects, entirely different mechanisms.

/media/content-media/a56f3ccd-38fe-490f-a5d3-6edb6bc228d5/2026/10/25f1596b-f00d-45e4-9d5e-43c91cf50084.png

Approval state machine (top) and approval sequence diagram (bottom). State machine: pending_approval moves to approved on human approval → executed, to rejected on human rejection, or to expired_auto_rejected on timeout; all three branches terminate at audited. Sequence: Agent initiates → approval queue → push notification → human confirms → executor runs → audit log written back, with timeout taking the deny-by-default branch. State names match the ApprovalStatus enum in the article's code example exactly.

What must go through approval: the risk × reversibility quadrants

The first instinct is usually "approve every write" — and three days later you'll turn the whole mechanism off out of approval fatigue, the most common cause of death for human-review systems. The right approach is tiering: only operations that are high-risk or irreversible deserve to interrupt a human. Use this quadrant table to grade your operations:

Reversible (one-click recovery)Irreversible (hard or impossible to recover)
High risk (touches users / money / data)Tier 2: approval required
e.g. bulk user-permission changes, payment-gateway config switches, large-scale repricing
Tier 1: approval mandatory
e.g. dropping databases/tables, bulk refunds/payouts, broadcasts to all users, revoking production keys
Low risk (small blast radius)Tier 4: execute directly
e.g. saving a draft, generating a report, querying data
Tier 3: log only
e.g. deleting a single test record, canceling one pending order — execute but leave a trail for post-hoc audit

In vibe projects, the four most common "must approve" categories are: deletion (dropping tables, buckets, user data), money (refunds, payouts, price changes, coupon issuance), outbound broadcast (SMS/email/push reaching real users), and permission changes (RBAC edits, issuing production secrets, opening public access). One litmus test: if this operation goes wrong, can I undo it completely within 5 minutes? If not, it goes through approval.

Write the agent rule as one sentence: "For any operation in the four categories above, calling the execution tool directly is forbidden; you must first create an approval ticket and wait for its status to become approved." The more specific the rule, the less the agent will "handle it flexibly" — "be careful with high-risk operations" means nothing to an agent.

The ticket data structure: minimal schema

The approval ticket is the core asset of the whole mechanism: it is both the agent's "construction permit" and the post-incident "black box." More fields are better than fewer, but below is the minimum viable version — any leaner, and after an incident you won't even be able to say "what was approved back then."

// Status enum: strictly consistent with the state machine in the diagram.
// New states must update the diagram before the code.
enum ApprovalStatus {
  pending_approval,       // created, awaiting human decision
  approved,               // human approved, waiting for the executor
  rejected,               // human rejected with reason, terminated
  expired_auto_rejected,  // timed out with nobody deciding: deny by default, reason=timeout
  executed,               // executor finished, execution result written back
  audited,                // archived: terminal state, the single exit of all branches
}

// Minimal approval ticket schema (Prisma-style sketch)
model ApprovalTicket {
  id            String         @id @default(uuid())
  type          String         // operation type: db.delete_table / payment.refund / notify.broadcast ...
  title         String         // human-readable: "delete pre-2024 test data from users table"
  actionSnapshot Json          // operation snapshot: pre-execution diff / SQL / full params; execution honors ONLY this snapshot
  snapshotHash  String         // hash of the snapshot; verified before execution: "what was approved is what runs"
  requester     String         // requester: agent name + session id, e.g. "claude-code/session-9f31"
  riskLevel     Int            // 1-4, matching the quadrant tiers
  status        ApprovalStatus @default(pending_approval)
  expiresAt     DateTime       // approval deadline; timeout transitions to expired_auto_rejected
  approver      String?        // decision maker
  decidedAt     DateTime?      // decision timestamp
  reason        String?        // rejection reason / timeout marker
  execResult    Json?          // execution result written back: success/failure, rows affected, rollback path
  createdAt     DateTime       @default(now())
}

Three design points, each paid for with real incidents:

1. The operation snapshot (actionSnapshot) is the soul. The ticket approves not the intent "drop a table" but "this exact diff, right now." The executor must verify snapshotHash before running — if the agent changed parameters while waiting for approval, a hash mismatch refuses execution. This defeats the bait-and-switch: approved as "drop the test table," executed as "drop the production table."

2. The requester must be session-precise. Logging just "claude-code" isn't enough; log down to session-9f31. In a post-mortem you need to answer "which conversation, which stretch of context gave the agent this idea" — coarse requester info is no info.

3. Three terminal branches, one unified exit: audited. approved must pass through executed before audited; rejected and expired_auto_rejected go to audited directly. The rule is iron: no ticket may vanish into thin air. A transition absent from the state machine must not exist in code — which is why this article's diagram and enum must match exactly: the diagram is the contract, the code is the implementation.

Notification and timeout policy: deny-by-default is the floor

A ticket nobody sees is a ticket that was never created. Notification policy solves "the human knows"; timeout policy solves "the human is away."

Notification channel: pick what the human WILL see, not what they "should" see. For a solo team the most reliable is a phone push (Bark / WeCom / a Telegram bot — any takes 5 minutes to wire up), with SMS as fallback; email is archive-only — nobody drops what they're doing for an email. The notification must deliver everything at once: operation title, risk tier, quadrant grade, snapshot summary, expiry countdown, and approve/reject buttons. Letting the approver decide from the lock screen within 30 seconds is what keeps this mechanism alive — an approval flow that requires opening an admin console won't survive two weeks in a solo team.

Timeout policy: deny-by-default, no exceptions. This is the most important half-sentence in the whole guide: when a ticket expires, the state machine may only move to expired_auto_rejected — never "auto-approve on timeout." Auto-approve is the absence of approval, and worse: it hands you the safety illusion of "I set up approvals." Default timeouts by risk tier: 15 minutes for tier 1, 2 hours for tier 2, 24 hours for tier 3. Don't set them too long — the longer the expiry, the longer the agent sits idle burning tokens; don't set them too short either — a 3-minute timeout just trains humans to click approve blindly.

Escalation chain: the second in line when the on-call is away. For a solo team the chain is simple: you → your backup contact method (e.g., escalate from push to a phone call) → auto-reject. Don't build elaborate multi-level escalation; small teams can't operate it. Teams with more people can add "the creator cannot approve their own ticket" — self-initiated, self-approved review is a rubber stamp.

Against approval fatigue: aggregation and batching. If the agent wants to drop 50 test tables, that must not create 50 tickets — auto-aggregate by "same type + same risk + same session" into one, titled "bulk delete of 50 test tables (see snapshot for details)." Approval fatigue is the number-one killer of human-review systems: the moment humans start approving without reading, the gate is pure ritual.

Audit trails: who approved what, when

The audited terminal state isn't "file and forget" — it's where the whole mechanism pays off. An audit record must answer four questions, and it's incomplete if any is missing: who (approver, down to the person), when (decidedAt, second precision, with timezone), approved what (full actionSnapshot + snapshotHash), with what outcome (execResult: success/failure, blast radius, rollback path).

All three branches leave trails, not just the approved ones: rejected must record the reason ("this table name looks like production — hold on" is worth its weight in gold in a review three months later), and expired_auto_rejected must record the timeout fact (repeated timeouts signal an unreasonable timeout setting, or operations that shouldn't require approval at all — that's input for re-tiering).

The audit log must be append-only: writes allowed, edits and deletes forbidden, retained at least 180 days. A solo project doesn't need a blockchain for this, but the "approval records live in the git repo, edits leave traces" property should hold — the simplest implementation writes every state change as an immutable record (an event log), with the current status being a fold over those events rather than an UPDATE-able field.

There's also a very practical payoff: enterprise customers. When your vibe project lands its first enterprise client, their security questionnaire will absolutely include "do high-risk operations have approval and audit." With this mechanism, you pass by pasting one state-machine diagram; without it, you're retrofitting two weeks before signing — and auditors can spot a retrofitted audit log instantly.

Emergency lane and post-hoc review: rules for breaking the glass

At 3am your database is saturated, and the agent says "I need to kill slow queries and restart the instance now" — the ticket goes out, you're asleep, and "deny by default" just killed your service. So the mechanism must include an emergency lane (break-glass), but the emergency lane isn't "bypassing approval" — it's "deferred approval."

Three rules. First, emergency execution must explicitly declare "I'm taking the emergency lane"; the executor records emergency=true and notifies everyone immediately (a belated witness beats no witness). Second, the emergency lane's scope is whitelisted in advance: only "hemostatic" operations — restarts, scaling, killing queries, traffic shifting — never data deletion or permission changes. You may break the glass to stop bleeding; you may not break it to amputate. Third, and most important: the 24-hour post-hoc review checklist — the first thing you do after waking up, item by item:

  • Confirm the blast radius: what changed, how many users were affected, whether data is consistent
  • Backfill the ticket: complete the never-finished approval as a "post-hoc approval" so the chain stays unbroken
  • Root-cause review: why did it come to the emergency lane? Missed monitoring alert, wrong tiering, or too-long timeout
  • Mechanism patch: the review's conclusion must land as one rule change (e.g., "downgrade this kind of restart to tier 3") — otherwise 3am will come again

One judgment to close with: the essence of human review isn't "distrusting AI" — it's admitting a fact: AI's cost of mistakes and your sleeping hours are misaligned. Its 3am "capability" needs your 3-minute daytime "nod" to hedge. This state machine plus sequence diagram runs in one weekend; and the first dropped-database incident it prevents pays for three years of maintenance.

Views 0Comments 0

Comments (0)

ME
0/1000
Loading comments...
Browse projectsPublish your project

Related articles

Slopsquatting attack-chain diagram: four attack steps on the left, matching interception action on the right
Guide
That Package Your AI Told You to Install Might Not Exist: Dependency Supply-Chain Security for Vibe Projects

AI confidently invents package names that don't exist — and attackers register them, waiting for you. A USENIX Security 2025 study found 19.7% of AI-generated code referenced nonexistent packages. This guide dissects the four-step slopsquatting attack chain and gives you a 5-minute pre-install review, lockfile pinning, CI defenses, and an incident-response SOP.

Developer WorkflowAI CodingSecurity & Privacy
Screenshot of web-edit's file browser: WORKSPACE / Files header above a file list with name, size, modification time and download/delete links, upload queue panel at the bottom
News
Don't Feed Secrets to the Model: Simon Willison Built an Out-of-Band File Editor from His Phone with Codex

Simon Willison shipped web-edit 0.1a0, a tiny Python tool: the agent runs the web UI remotely, and he edits files directly from his phone over Tailscale — so credentials files never round-trip through the LLM's context. The tool itself was built with Willison directing Codex Remote from his phone, GPT-6 Astra Extra High doing the writing.

Developer WorkflowOpenAI CodexOpen Source
A padlock on a laptop keyboard, symbolizing web security protection
Guide
Don't Ship Your Vibe Project Naked: A Web Security Baseline Playbook (CSP, CSRF, XSS, SQL Injection)

AI writes code fast but never writes secure code by default: running locally is not the same as being safe in production. This hands-on playbook fills the web security baseline for your vibe project — CSP headers, CSRF tokens, XSS defense, SQL parameterization, the cookie triple, dependency supply-chain gates, plus a copy-ready 10-item pre-launch acceptance checklist.

Backend EngineeringIndie DevelopmentFrontend Engineering