An AI-assisted development workflow that ships code

AI coding assistants are everywhere now — Claude Code, Cursor, Copilot. Getting them to autocomplete a line is easy. Getting them to help you ship a real feature, into a real codebase, without quietly introducing a bug you’ll chase for two days — that’s a skill. This is the workflow I actually use as a senior engineer, and the guardrails that keep the quality high.

What AI is good at — and what it isn’t

The fastest way to be disappointed by an AI assistant is to ask it for the thing it’s worst at. A useful mental model: treat it like a very fast, tireless junior pair-programmer. Brilliant throughput, needs supervision.

It’s strong at: boilerplate, tests, scaffolding, working with an unfamiliar API, mechanical refactors, explaining existing code, and producing a solid first draft you can shape.

It’s weak at: architecture decisions, subtle correctness, matching your codebase’s conventions, and anything security-sensitive. It will also state wrong things with total confidence. Your job is to aim it at the first list and stay in the loop on the second.

The workflow, step by step

1. Frame the task tightly

Vague prompts produce vague code. Before I ask for anything, I give the assistant the context it can’t guess: the framework and version, the relevant files, the constraints, and what “done” looks like. “Write a function to send emails” gets you generic junk. “Add a queued job that sends the order-confirmation email via our existing BrevoMailer service, retries 3 times, and is covered by a feature test” gets you something you can use.

2. Architect first, generate second

Decide the shape of the solution yourself — the boundaries, the data flow, where the new code lives. Let the AI fill in the implementation inside those boundaries. The architecture is the part that’s expensive to get wrong and cheap for you to decide; the implementation is the part that’s tedious for you and fast for the AI. Don’t trade those roles.

3. Review like a senior reviewing a PR

Read every line before it lands — the same way you’d review a junior’s pull request. You’re looking for the things AI gets wrong often: silent error-swallowing, N+1 queries, missing edge cases, a subtly wrong assumption about your domain. If you wouldn’t approve it from a teammate, don’t approve it from a model.

4. Verify by running, not by reading

Code that looks right and code that is right are different things. The single biggest quality lever is to actually exercise the change — run the test, hit the endpoint, trigger the job. AI is very good at producing plausible code; plausible is not the bar. Running it is.

5. Keep a human gate on the risky parts

Migrations, auth, payments, anything that deletes data, anything that touches money or secrets — slow down and own those personally. Let AI draft them if you like, but the decision to ship is yours, with full understanding of what the code does.

A concrete example

Say I need that order-confirmation job in a Laravel app. I frame it tightly, let the assistant draft the job and a test, then I review and run. Here’s roughly the generated job:

<?php

namespace App\Jobs;

use App\Models\Order;
use App\Services\BrevoMailer;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;

class SendOrderConfirmation implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable;

    public int $tries = 3;
    public int $backoff = 30;

    public function __construct(public Order $order) {}

    public function handle(BrevoMailer $mailer): void
    {
        $mailer->send(
            to: $this->order->customer_email,
            subject: "Your order #{$this->order->id} is confirmed",
            template: 'emails.order-confirmation',
            data: ['order' => $this->order],
        );
    }
}

This is a good draft. But I don’t trust it until I’ve checked the parts AI tends to miss: Does BrevoMailer::send() actually have that signature in our codebase, or did it invent one? What happens on the 3rd failure — does it dead-letter, or vanish? Is Order safe to serialize onto the queue? Then I run the feature test it wrote and watch it actually enqueue and send against a fake mailer. The draft saved me ten minutes of typing; the review and the run are what make it shippable.

Guardrails that keep quality high

  • Small diffs. Ask for one focused change at a time. Huge AI-generated dumps are hard to review and easy to rubber-stamp.
  • Tests are non-negotiable. Have it write the test too, then make the test fail first so you know it’s real.
  • Never paste secrets into a prompt — keys, tokens, customer data, proprietary code you can’t share.
  • Verify external facts. If it cites an API, a flag, or a version, confirm it in the real docs. Confident ≠ correct.
  • Keep your conventions. Tell it your patterns, or it’ll invent its own and fragment the codebase.

The takeaway

AI-assisted development isn’t about handing the keyboard to a model. It’s about moving faster on the tedious 80% while staying firmly in control of the 20% that actually matters. Frame tightly, architect yourself, review every line, verify by running, and guard the risky parts. Do that, and the assistant becomes a genuine multiplier instead of a bug generator.


← All posts