Your codebase doesn't remember why.

import time
from payments.gateway import StripeClient
from orders.models import Order, PaymentAttempt

# Subsystem: docs/subsystems/payment_pipeline
# Chunk: docs/chunks/checkout_retry

def process_checkout(order: Order, token: str) -> PaymentAttempt:
    """Process payment with vendor-aware retry logic."""
    client = StripeClient(api_key=order.merchant.stripe_key)

    for attempt in range(3):
        try:
            result = client.charges.create(
                amount=order.total_cents,
                currency=order.currency,
                source=token,
                idempotency_key=f"{order.id}-{attempt}",
            )
            return PaymentAttempt.record(order, result, success=True)

        except client.RateLimitError:
            # Decision: docs/trunk/DECISIONS.md#stripe-retry-policy
            time.sleep(3)

        except client.CardError as e:
            return PaymentAttempt.record(order, e, success=False)

    raise CheckoutExhaustedError(order_id=order.id, attempts=3)
import time
from payments.gateway import StripeClient
from orders.models import Order, PaymentAttempt

def process_checkout(order: Order, token: str) -> PaymentAttempt:
    """Process payment with vendor-aware retry logic."""
    client = StripeClient(api_key=order.merchant.stripe_key)

    for attempt in range(3):
        try:
            result = client.charges.create(
                amount=order.total_cents,
                currency=order.currency,
                source=token,
                idempotency_key=f"{order.id}-{attempt}",
            )
            return PaymentAttempt.record(order, result, success=True)

        except client.RateLimitError:
            time.sleep(3)

        except client.CardError as e:
            return PaymentAttempt.record(order, e, success=False)

    raise CheckoutExhaustedError(order_id=order.id, attempts=3)

An agent reading this code knows where it came from, why it exists, and what it's allowed to change.

An agent reading this code has to guess why it exists.

Day 2

Vibe coding is magic on day 1. You describe what you want, the agent builds it, and it works.

Day 2, you ask for a change. The agent doesn't know why anything was built the way it was. It guesses. It breaks things. You start over, or you stop trusting it.

The problem isn't the agent. It's that your codebase contains only the result, not the reasoning.

Engineering isn't really writing code

The valuable part is the architectural judgment: what constraints matter, what decisions to make, what tradeoffs to accept. The code is what implements that judgment.

Day 2 breaks because the codebase kept the implementation but not the judgment that produced it. The agent reads the code, can't reconstruct the why, and "fixes" things it shouldn't touch.

VE adds the missing layer: a record of the judgment, bound to the code that implements it.

Chunks

A chunk is a piece of architecture work bound to implementation. It captures the constraints, decisions, and boundaries that give a piece of the system its shape, then holds that record steady as the code evolves underneath it.

Code says how the system works: mutable, refactorable, tactical. Chunks say why a piece of the system has the shape it has. Together they're the architecture.

Capture the intent. The goal records the problem, the success criteria, and the constraints in present tense. It's the contract the chunk holds the code to, and it stays current as the code evolves.

Bridge the codebase to the goal. The plan is the agent's literate-programming pass through the work: ordered steps, references to existing code, an articulation a reviewer can verify. A surprising plan means the goal wasn't specific enough.

Write the code. The agent works through the plan. When it writes code the chunk's intent governs, it adds a backreference comment pointing back to the chunk. The codebase gains context as it grows.

Bind the chunk to the code it produced. The chunk records its code references, status flips to ACTIVE, and the linkage is permanent. Future agents follow backreferences from the code back to the architectural intent that shaped it.

As chunks accumulate, the codebase teaches the next agent. Context gets discovered at the point it's relevant, not all at once.

The hardcoded retry

Look at the example above again. time.sleep(3). Any engineer would "fix" that to exponential backoff. Any agent would too.

But the backreference points to this:

Decision Record

Stripe retry policy. The vendor's rate limiter bans clients that retry faster than 3 seconds. We discovered this during the Nov 15 2024 incident when exponential backoff (starting at 100ms) triggered a 24-hour IP ban during peak checkout.

Fixed sleep of 3 seconds is the only correct retry interval. Do not change without re-testing against the vendor's rate limiter in staging.

2024-11-15
Code can look wrong and be exactly right. Without the reasoning, the next agent to touch it will "fix" it.

Greenfield or legacy

The same workflow works on a brand-new project and on a legacy codebase you're retrofitting. Run ve init in either, document your next chunk of work, and the backreferences accumulate as you go.

Once the architecture is staked out in chunks, the orchestrator turns implementation into a team. Each chunk runs in its own worktree with its own agent; they land in parallel as their work completes, each as its own commit on your branch. The judgment is yours. The typing isn't.

$ uv tool install vibe-engineer
Other install methods
$ pip install vibe-engineer
Open Source