Writing

One Command from Plan to Commit: Wiring the Whole Pipeline Together

One Command from Plan to Commit: Wiring the Whole Pipeline Together - abstract illustration

I've written separately about the habits that make AI-assisted coding actually work: plan before you write a line, match the model to the phase, have a second model review the first. Each of those is a real improvement on its own. But run by hand, they're also friction. You have to remember to ask for the plan, remember to switch models, remember to open a clean context for review. The habit you skip is the one that would have caught the bug.

So I stopped running them by hand. I wired the whole sequence into a single command - I call it /ship - that takes a task from a one-line description to a reviewed commit without me re-driving each step. This is what it does, why it's built the way it's built, and why the wiring is worth more than the sum of the steps.

The pipeline in one command

When I hand /ship a task, it runs six steps in a fixed order:

  1. Architect. A planning agent reads the task, pulls in the project's reference docs for the stack it's touching, and produces a concrete plan: the files it will change, the approach, the edge cases, the interfaces. It shows me the plan and stops. Nothing gets written until I approve it.
  2. Implement. Once I approve, a capable model implements the plan directly, honoring the patterns and gotchas the architect surfaced.
  3. Test. A separate agent writes unit tests for the new code, runs them, and fixes what fails.
  4. Document. It updates the docs the change actually affects - the project's architecture notes, and the stack reference library if the change surfaced a new gotcha - and leaves untouched docs alone.
  5. Review. It stages the diff and hands it to a reviewer agent with a clean context whose only job is to find what's wrong.
  6. Commit. If the review is clean, it commits. If not, it fixes the findings and re-reviews until it is.

That's the whole task, start to finish, from one invocation. The value isn't that any single step is novel. It's that the order is enforced and nothing gets quietly dropped.

Each step has one job

The steps aren't one model doing everything in one long conversation. They're distinct agents, each with a narrow job and, critically, a fresh context between the ones that need it.

This matters most at the boundary between building and reviewing. The model that just wrote the code is the worst reviewer of it - it's anchored on every choice it already made and biased toward agreeing with itself. The reviewer in step five has never seen the implementer's reasoning. It gets the diff, the files, and the task, and nothing about how the code came to exist. That single separation is most of what makes the review pass honest instead of a rubber stamp.

The same logic runs through the whole chain. The architect plans without being distracted by implementation detail. The implementer builds against a fixed plan instead of re-deciding the architecture mid-file. The test author writes tests without having been the one who convinced itself the code was already correct. Splitting the work into single-responsibility roles isn't organizational tidiness - it's what keeps each step from inheriting the last step's blind spots.

The right model at each step

Because the steps are separate, each one runs on the model that phase actually needs, which is the match-the-model discipline baked into the command instead of left to my memory.

Planning and review are low-volume, high-leverage: a few hundred words of output where a wrong call is expensive. Those run on a strong reasoning model. Implementation is high-volume and, once the plan is solid, closer to transcription than invention - that runs on a fast model that's roughly an order of magnitude cheaper for the same tokens. Test authoring sits in the middle. The command wraps two thin slices of expensive reasoning around a thick middle of cheap generation, and I never have to think about the switch. It happens because the pipeline is built that way.

The point I keep coming back to is that "which model" was never one decision. It's a decision per phase, and hard-coding it into the command is how I stop paying top-tier rates for bulk generation without having to remember to downgrade every time.

The plan gate is a human gate

Step one ends by stopping. The architect shows me the plan and waits. This is deliberate, and it's the one place the automation intentionally refuses to be autonomous.

A plan is cheap to read and cheap to change. Code built on a wrong plan is expensive to unwind. Reading a few hundred words before any code exists is the highest-leverage minute in the whole task - it's where I catch "you're about to touch the wrong module" or "this misses the concurrent case" while it still costs nothing to fix. This is knowing which work to keep behind a human gate: I delegate the typing, I keep the architectural go/no-go. The command is built to make that gate unavoidable rather than optional, because the plan I skip approving is the plan that ships the wrong thing correctly.

Review before commit, in a loop

The last thing that happens before a commit is an adversarial read, not a green checkmark. The reviewer isn't asked "does this look okay" - it's asked to assume the diff is broken and find where. It returns findings as structured items, each with a location and a claim, not three paragraphs of prose I have to re-parse. Structured output is what lets the pipeline act on the review instead of just displaying it: a real finding sends the task back for a fix, a clean review advances it to commit.

And it loops. Fix, re-review, fix, re-review, until the diff comes back clean. The commit is the thing that happens after review passes, never the thing that happens instead of review. That ordering is the whole point of putting it in a command - by hand, "commit" and "review it later" collapse into the same tired keystroke at the end of the day. Wired into the pipeline, review is load-bearing.

Why wire it instead of doing it by hand

Every step in /ship is something I could do manually, and for a long time did. The reason to spend the effort wiring it into one command comes down to three things.

Sequence enforcement. The steps that get skipped by hand are exactly the unglamorous ones - the plan, the tests, the review - and they're the ones that catch problems. A pipeline can't skip a step to save five minutes. It runs the whole sequence every time, including on the Friday-afternoon change where I'd have cut the corner.

One invocation, not six decisions. Every manual handoff is a chance to forget the model switch, forget the clean context, forget to stage before review. Collapsing six decisions into one removes six opportunities to do it wrong.

Consistency across every task. The small change and the big change get the same rigor. I'm not deciding case by case whether this one is "worth" a review pass, which means I never talk myself out of the review on the change that turns out to need it most.

The mental model

The habits I've written about are each a good practice in isolation. The step past "good practice" is making the practice the path of least resistance - the thing that happens by default because doing it any other way takes more effort, not less. A pipeline does that. It turns "I should plan first" and "I should have something review this" from intentions I have to summon into steps that run whether or not I remember them.

Wire the sequence once, put the right model and a clean context at each step, gate the plan on yourself, and let the command carry the discipline you'd otherwise have to carry by hand. The best workflow is the one you can't accidentally skip.

Building something like this?

This is the kind of work I do for clients. Tell me what you're building and I'll give you a straight read on the approach.

Book a 30-minute call