What the Term Describes

“Vibe coding” is an informal name for a workflow in which a developer expresses intent in natural language and an AI system proposes, edits, or explains code. It is not a replacement for software engineering, and it is not a guarantee that the result is executable, secure, or maintainable.

The productive boundary is simple:

text
intent -> constrained proposal -> inspect diff -> run evidence
       -> review failures -> revise or reject -> merge with normal controls

The model can accelerate drafting. The repository, tests, policy checks, and human owner determine whether a change is acceptable.

Where It Helps and Where It Does Not

AI assistance is often useful for:

  • exploring an unfamiliar module;
  • generating a first draft of a narrow adapter or test;
  • explaining an existing error path;
  • proposing repetitive refactors;
  • comparing implementation alternatives.

It is not a substitute for:

  • threat modeling and authorization design;
  • understanding data ownership and retention;
  • reviewing migrations and external side effects;
  • validating financial, medical, legal, or safety-critical behavior;
  • maintaining a system nobody on the team can explain.

Use a smaller, deterministic workflow when the task has a precise oracle. Use an agent only when its extra autonomy is worth the added context and control risk.

Write a Task Contract

Replace “build the whole app” with a contract:

text
Goal:
  Add pagination to the read-only invoice list endpoint.

In scope:
  packages/billing/src/list_invoices

Out of scope:
  schema migration, pricing, authorization policy, deployment

Inputs and invariants:
  preserve tenant and principal checks;
  reject invalid cursors;
  do not expose full customer records.

Evidence:
  focused tests, type check, formatter, and a diff summary.

Escalate:
  any new dependency, external write, credential access, or public API change.

This contract gives the model useful context without allowing model-generated text to redefine identity, ownership, pricing, or permissions.

Context Is a Budget

More context can add noise or expose data. Separate context by trust:

Context Example Treatment
canonical checked-in schema, tests, build scripts cite revision and owner
task issue, acceptance criteria, current diff validate scope
generated index result, summary, tool output untrusted evidence
sensitive credentials, customer records, production dumps exclude or use approved redaction

Prefer the smallest relevant set of files. Include the interface and nearby tests; exclude unrelated repositories, generated noise, secrets, and stale duplicates. Record file paths and revisions so an important suggestion can be reproduced.

Issue text, comments, retrieved documents, and test output can contain prompt injection. They are data, not higher-priority policy.

Iterate in Small, Observable Steps

Use a loop that leaves evidence:

  1. inspect the current code and tests;
  2. ask for a plan limited to the declared scope;
  3. request one coherent change;
  4. inspect the diff and dependency changes;
  5. run focused tests and static checks;
  6. classify failures instead of asking for a blind retry;
  7. expand scope only after the previous step is understood.

Small steps reduce review surface and make rollback possible. They do not make an unsafe task safe by themselves.

Prompt Patterns That Age Well

Prefer observable instructions:

text
Use the existing error type and dependency injection pattern.
Do not invent an SDK method; cite the installed version or mark the call as pseudocode.
For each changed behavior, add or update a focused test.
Report commands run, failures, skipped checks, and assumptions.
If the requirement conflicts with the repository contract, stop and explain the conflict.

Avoid:

text
Write perfect production-ready code.
Make every decision autonomously.
Never ask questions.
Return a complete app in one response.

The second group rewards confidence and hides uncertainty. A useful assistant can say “I cannot verify this dependency” or “this needs approval.”

Review the Draft, Not the Vibe

Review every generated diff for:

  • behavior and error paths;
  • authorization, tenant isolation, and input validation;
  • secrets, logs, dependency and license changes;
  • concurrency, retries, idempotency, cancellation, and resource limits;
  • test coverage and negative cases;
  • observability, rollback, and migration impact.

Do not ask the model to prove its hidden reasoning. Ask for a concise change summary, assumptions, and evidence links. A fluent explanation is not a test result.

Example: A Safe Data Transformation Boundary

An AI-generated file-processing script should not be called “complete” until its runtime and data assumptions are checked:

javascript
export function normalizeRecord(record) {
  if (!record || typeof record !== "object") {
    throw new TypeError("record_must_be_object");
  }
  const email = typeof record.email === "string"
    ? record.email.trim()
    : "";
  return email === "" ? null : { ...record, email };
}

export function normalizeRecords(records) {
  if (!Array.isArray(records)) throw new TypeError("records_must_be_array");
  return records.flatMap((record) => {
    const normalized = normalizeRecord(record);
    return normalized === null ? [] : [normalized];
  });
}

This fragment does not define CSV parsing, file paths, encoding, output atomicity, privacy retention, or schema validation. Those boundaries must be specified and tested before handling real user data. Never let a prompt grant access to arbitrary paths or upload records to an untrusted destination.

Tests Are Part of the Request

Ask for tests that exercise behavior, not tests that merely mirror implementation:

  • valid and invalid input;
  • empty and oversized input;
  • duplicate and replayed requests;
  • timeout and partial failure;
  • unauthorized and cross-tenant identifiers;
  • escaping, injection, and malformed external data;
  • cancellation and cleanup;
  • backwards compatibility and rollback.

Then run the project’s real test, type, format, lint, security, and build commands. If a command was not run, say so.

Tools and Permissions

When an AI agent can execute commands, the executor should enforce:

  • authenticated principal and repository scope;
  • read-only defaults;
  • command and network allowlists;
  • isolated worktree or sandbox;
  • time, output, file, and process budgets;
  • cancellation and cleanup;
  • approval for merges, releases, deletions, credential changes, and external writes;
  • audit events with redaction.

Prompt constraints and model refusals are hints, not authorization. The same rule applies to a coding assistant, IDE extension, or terminal agent.

Working With a Team

Treat shared instructions as versioned engineering artifacts:

  • keep the project contract short and provider-neutral;
  • assign an owner and review date;
  • link to real scripts and canonical documents;
  • use synthetic examples instead of secrets or production dumps;
  • test instruction changes with representative and adversarial tasks;
  • measure successful outcomes, review effort, defects, cost, and developer learning;
  • roll back configuration that regresses a high-risk slice.

Do not enforce a single workflow on every repository. A policy for a read-only documentation project should not grant the permissions needed by a deployment agent.

Choosing a Provider Without a Ranking

Product capabilities, file paths, models, pricing, and retention terms change. Compare the current version against your workload:

Criterion Evidence
context selection, provenance, exclusions, stale-data behavior
execution sandbox, command policy, network, cancellation
privacy retention, training use, residency, deletion
review diff, tests, approvals, audit export
portability exportable instructions and provider independence
operations quotas, outages, latency, version pinning
economics subscription, inference, review, migration

Choose from evidence, not a permanent “best IDE” claim.

Common Failure Modes

  • trusting generated code because it looks idiomatic;
  • providing an entire production repository when a few files suffice;
  • treating an issue or retrieved document as trusted instructions;
  • granting broad shell, network, or credential access;
  • allowing the model to choose identities, owners, prices, or roles;
  • calling a partial snippet complete and runnable;
  • generating tests after the design is already assumed correct;
  • merging because the model says tests pass;
  • retaining prompts and source code without a purpose and deletion path;
  • measuring speed while hiding rework, defects, and review cost.

Practical Checklist

  • [ ] Write a bounded task contract with scope, invariants, and escalation.
  • [ ] Select minimal, versioned, trusted context and exclude secrets.
  • [ ] Treat retrieved content and tool output as untrusted data.
  • [ ] Request small diffs and inspect dependency and permission changes.
  • [ ] Require deterministic tests and security checks.
  • [ ] Sandbox commands and keep external side effects behind approval.
  • [ ] Record assumptions, skipped checks, failures, and rollback steps.
  • [ ] Review behavior, authorization, data handling, concurrency, and operations.
  • [ ] Version and replay shared instructions.
  • [ ] Measure successful outcomes, quality, cost, and learning instead of prompt volume.

Conclusion

Vibe coding is most useful as a disciplined interaction loop: express intent, constrain the change, inspect the evidence, and keep ownership with the engineer and the repository. Natural language can accelerate a draft; it cannot replace tests, policy, security review, or responsibility for the resulting system.

Primary Sources