Vibe Coding Is Fun Until the AI Drops a Table in Production

AI coding agents can write, run, and deploy code — all in one shot. That's the point. It's also the risk. Here's how to keep vibe coding sessions from turning into production incidents.

Vibe coding is real and it's genuinely good. You describe what you want, the AI writes the code, runs tests, fixes errors, deploys. The feedback loop collapses from minutes to seconds. Entire features appear while you're still holding your coffee.

The problem isn't the AI's ability to write code. The problem is that writing code and executing commands on your infrastructure are very different risk profiles — and most vibe coding setups treat them identically.

When Codex, Claude, or Cursor runs npm test, that's fine. When it runs psql production -c "DROP TABLE sessions" to "clean up test data" — that's a different story. And unlike a human, the AI doesn't pause before destructive commands. It just runs them, because you told it to "clean up."

The actual failure modes

These aren't hypothetical. They're patterns that emerge naturally from how AI coding agents work:

1. Context collapse

You're working in dev. You tell the agent to "run the migration to add the new column." The agent runs it — on production, because the DATABASE_URL env var pointed there and the agent didn't know to check. The migration runs. It works. You now have a new column in production before you tested it anywhere else.

The agent did exactly what you asked. You just didn't specify which database.

2. Cleanup that isn't

You ask the agent to "clean up the temporary files from that last run." The agent interprets this broadly, deletes some build artifacts, then also removes a cache directory that turned out to be the persistent session store. Your users' sessions are gone. The agent was thorough.

3. The helpful rollback

Something is broken. You ask the agent to fix it. The agent decides the cleanest fix is to roll back to the previous deployment. It does. What the agent didn't know: the previous deployment had a security patch removed. You're now running vulnerable code and you don't know why.

4. Scope creep in shell commands

You ask the agent to "restart the backend so the config change takes effect." The agent runs pkill -f expacti-backend, which kills the process. Then it notices the process isn't coming back up and, trying to be helpful, runs additional commands to investigate — reading config files, checking logs, eventually trying to restart other services it thinks might be related.

What started as a one-command restart became a five-command debugging session, with each command potentially affecting production state.

🔴 The common thread

In all four cases, the AI did what it was told — or what it reasonably inferred you wanted. The problem isn't intelligence failure. It's that there was no checkpoint between "AI decides to run a command" and "command runs on production."

Why "just sandbox it" isn't enough

The standard advice is to give AI agents sandboxed environments with no production access. This is good advice. It's also incomplete.

At some point the code has to ship. The deployment, the migration, the config change — all of that eventually hits production. You can sandbox the development loop all you want, but deployment is an inherently production-touching activity.

More importantly, many useful vibe coding workflows require production access. Debugging a production issue. Backfilling data. Running a one-off query. Applying a hotfix. If you sandbox everything, you've removed the AI agent from exactly the situations where it's most valuable — and most risky.

What you actually need isn't a wall between AI and production. You need a gate. Let the AI do the work; intercept before execution; give a human 30 seconds to say yes or no.

What command-level interception looks like in practice

Here's a vibe coding session with expacti in the loop. The developer is using Claude to debug a slow query in production:

# Developer prompt to Claude:
# "The /api/sessions endpoint is slow. Find the slow query and fix it."

# Claude decides to run EXPLAIN ANALYZE on the query
EXPACTI: Command pending approval
  Command: psql $DATABASE_URL -c "EXPLAIN ANALYZE SELECT * FROM sessions WHERE org_id = $1 ORDER BY started_at DESC LIMIT 50"
  Risk: LOW — 12   (read-only EXPLAIN, no data modification)
  Context: debugging /api/sessions performance

# Reviewer approves — 8 seconds later
✓ Approved by [email protected]

# Claude sees the query plan, identifies missing index
# Claude proposes: CREATE INDEX CONCURRENTLY on sessions(org_id, started_at)

EXPACTI: Command pending approval
  Command: psql $DATABASE_URL -c "CREATE INDEX CONCURRENTLY idx_sessions_org_started ON sessions(org_id, started_at DESC)"
  Risk: MEDIUM — 41  (DDL on production table, CONCURRENTLY is safe but irreversible)
  Context: fixing slow query identified in prior step

# Reviewer approves — 22 seconds later (read the migration, decided it was safe)
✓ Approved by [email protected]

The entire debug-and-fix loop ran in under 5 minutes, fully AI-driven. Two commands touched production. Both had a human in the loop. The EXPLAIN ran without friction (low risk, fast approval). The DDL got a second of scrutiny (medium risk, reviewer actually read it).

That's the point: not every command needs the same amount of friction. The risk score determines how much attention is warranted.

Risk scoring for shell commands

Expacti scores every command on a 0–100 risk scale before presenting it for approval. The scoring engine covers 14 command categories with 25 modifiers:

Command Risk Why
git status LOW — 5 Read-only, no side effects
npm test LOW — 10 Local execution, deterministic
git push origin main MEDIUM — 45 Permanent state change to main branch
psql prod -c "UPDATE users SET..." HIGH — 72 Direct production DB write
DROP TABLE sessions CRITICAL — 95 Destructive DDL, unrecoverable
kubectl delete deployment/api CRITICAL — 98 Production service termination

The whitelist handles the repetitive safe commands. Once you've approved npm test a few times, it runs automatically. Once you've approved the specific migration pattern your CI uses, that passes without interruption. The AI agent's routine work flows freely; novel or higher-risk actions get flagged.

Setting up expacti for AI coding sessions

The typical setup for a vibe coding workflow:

Option A: Wrap the agent's shell access

If your AI agent calls shell commands through a specific binary or script, wrap it with expacti-sh:

# Instead of the agent running commands directly:
EXPACTI_BACKEND_URL=wss://api.expacti.com/shell/ws \
EXPACTI_SHELL_TOKEN=<your-token> \
expacti-sh

Every command the agent types into this shell is intercepted. The agent's development loop continues at full speed; only commands that exceed your risk threshold pause for approval.

Option B: MCP tool integration

If your AI agent uses MCP tools, the expacti MCP server provides an exec tool that routes through the approval queue. The agent calls exec(command="..."), expacti intercepts, you approve, the result comes back to the agent.

# In your MCP config:
{
  "mcpServers": {
    "expacti": {
      "command": "expacti-mcp",
      "env": {
        "EXPACTI_URL": "wss://api.expacti.com/shell/ws",
        "EXPACTI_TOKEN": "<your-token>"
      }
    }
  }
}

Option C: SSH proxy

If your AI agent SSHs into production machines, expacti-sshd acts as a transparent SSH proxy. The agent connects through it; every command in the session is intercepted before reaching the real server.

# Agent SSH config:
Host production
  HostName expacti-sshd.your-infra.com
  Port 2222
  User agent-user

# All SSH session commands go through expacti's approval queue

This approach requires zero changes to the AI agent. It SSH's to "production" as normal; expacti is invisible until something needs approval.

Tuning the friction level

The most common complaint about human-in-the-loop systems is that they slow everything down. That's a tuning problem, not an inherent tradeoff.

Three levers:

  1. Whitelist aggressively. Any command pattern you trust unconditionally should be on the whitelist. The AI suggestion engine proposes patterns based on your approval history — accept the ones that make sense. Your vibe coding session shouldn't be interrupted by cargo test -p backend for the 50th time.
  2. Set the risk threshold. By default, everything requires approval. You can configure auto-approve below a risk score threshold — say, anything under 20 runs without review. Adjust based on your risk tolerance.
  3. Use anomaly detection selectively. Expacti's anomaly engine flags commands that are unusual for the time of day, the session, or the command history. If you're doing a late-night vibe coding session, you might want tighter scrutiny than your usual approval flow provides.
💡 The 80/20 of approval friction

In practice, after the first week of a vibe coding setup, 80–90% of commands auto-approve via whitelist. The remaining 10–20% are things you actually want to review: first-time deployments, DDL changes, anything touching production data. The total overhead is a few seconds per hour of coding.

The audit trail benefit

Vibe coding sessions with AI agents are notoriously hard to audit. Did the AI modify the database directly? Which commands ran in that debug session yesterday? What exactly did it deploy?

With expacti in the loop, every command is logged: timestamp, exact command text, risk score, whether it was approved or denied, who approved it, how long the review took. Commands run automatically via whitelist are logged as whitelist-approved with the matching rule.

When something goes wrong — and something always eventually goes wrong — you have a complete record of every command that ran in every AI agent session. Not just the code that was written, but the commands that were executed.

For teams using AI agents in CI/CD

If you're running AI coding agents in CI pipelines that touch production (deployments, migrations, data backfills), the GitHub Actions integration applies the same approval gate to your CI workflow:

- name: AI-proposed migration
  uses: kwha/expacti-action@v1
  with:
    command: ${{ steps.ai-agent.outputs.migration-command }}
    expacti-url: ${{ secrets.EXPACTI_URL }}
    shell-token: ${{ secrets.EXPACTI_SHELL_TOKEN }}

The AI generates the command; expacti intercepts it; a human reviews the actual SQL before it runs against production. The AI agent's output is used but not blindly trusted.

The meta-point

The whole appeal of vibe coding is that you can move fast. Human-in-the-loop sounds like the opposite of that. The insight is that read operations and safe local commands should be fast — and they are, because they hit the whitelist. What should be slow is the irreversible stuff: the DDL migrations, the production deployments, the data deletions.

Those were slow before AI agents too. You'd check the command three times before running it. You'd ask a colleague to review the migration. You'd create a change request ticket.

The expacti model is just that same careful human judgment, but made explicit, logged, and integrated into the tool the AI agent is already using. The vibe stays. The blast radius shrinks.

Let the AI code. You keep the gate.

Add expacti to your vibe coding setup in under 10 minutes. Command-level approval, risk scoring, audit trail — without slowing down the loop for things that don't need review.

Get early access See the demo