VEITH.DEV

← Blog

I Did Not Write It. I Own It.

Aug 21, 2026 · 8 min read

agenticdxworkflowreviewgitlab
Hero: I DID NOT WRITE IT. I OWN IT. Left card, vibe coding: accept all, read nothing; see if it runs, forget the code exists, nobody's name on it. Right card, inverted, this: type nothing, read everything; spec, plan, worktree, hooks; adversarial pass, then me; 327 of 383 merges, a click. The rule: guidelines shape form, a reader checks whether it is true.

Most of the commits in my two main repositories were written by Claude Code sessions. One person reads them and merges them, and that person is me. This is the first of three posts on how that works: what runs between an issue and a merge, what I do in that loop, and one issue followed from spec to merge. The issue is a marketing site built in a day, chosen because what review found on it is easy to picture.

People ask whether this is vibe coding. Karpathy's term from February 2025 means accepting every diff without reading it and seeing whether the result runs. What I do is closer to the opposite. I type very little and read more code than I ever wrote.

TL;DR: A session starts with the board in front of it and cannot open a worktree without an open issue. It builds from a written spec and a plan, one subagent per task. An adversarial review pass runs before the merge and writes its findings as commits and issues. I read the diff and the findings, answer the questions the plan left open, and click merge. Every commit carries my name, because attribution is switched off on purpose.
  • Session start. A hook prints the board: in progress, critical, high. Plain bash, no model call. I do nothing.
  • Worktree. A gate blocks any worktree not named <issue>-<slug> against an open issue and moves the issue to in progress. Another hook hands it its own port offset. I do nothing.
  • Spec and plan. A brainstorm produces a spec, and a plan is written from it with a verification command per task. I approve the spec and answer the questions it leaves open. The spec goes into git; the plan stays on disk.
  • Build. One subagent per task, a reviewer between tasks. Every commit ends in Refs #<issue> and carries its reason in the body. I do nothing.
  • Review. A whole-branch pass tries to prove the code wrong. It leaves fix commits and follow-up issues, filed before the merge. I read the diff and the findings and decide which are real.
  • Merge. The MR template checks that follow-ups were promoted to issues. A Stop hook adds Closes #<issue> if the session forgot. I click merge.

One issue, start to finish

The issue was the marketing site for one of our products: seven routes, a hero, a tabbed use-case section, pricing, FAQ and the search and answer-engine layer. The scope said pricing is contact only. Times are local.

issue #423, local time
12 AUG 10:05 Design spec committed, 745 lines. Every product claim checked
against the code first, with a list of what must not be claimed.
11:37 Plan committed, 2,269 lines, fifteen tasks. Three questions left
open for me, each isolated to one file.
11:37+ Build in worktree 423-landing-2kw-io, one subagent per task.
14:49 First review commit: "three fixes from actually running the
site rather than trusting the build".
15:27 "Four owner answers land here." My answers, applied.
15:36 Placeholder brand mark removed.
22:28 MR marked ready.
13 AUG 07:53 Invented favicon replaced with the application's real one.
10:41 Three hardcoded colours corrected to the brand values.
11:25 Merged. 15 commits, 43 files.
18:23 Follow-up bug #430 merged: the site was never going to build.

About 25 hours from spec to the merge that made it deployable. The sections below take the parts of that day that matter.

Run the thing before you trust the build

The build was green, lint was clean, the rendered-HTML assertions passed. The first review commit came from opening the site in a browser instead:

  • /favicon.ico returned 404. No icon existed.
  • The use-case panel put a prose column about 1,200 pixels wide beside a mock about 370 pixels wide, so half the section was empty.
  • A CSS rule meant to keep the tabs readable without JavaScript was dead code. Tailwind's reset sets display: none !important on hidden elements and nothing in the page could override it.

The last one is the one to remember. The site did work without JavaScript, but for a different reason than the comment next to the rule claimed: the server never emits the hidden attribute at all. The rule was wrong, the comment was wrong, and the guarantee held anyway. The commit fixed the comment and pointed it at the assertion that was already doing the real work.

A passing build says the tests you wrote agree with the code you wrote. It does not say whether the page does what the comment claims.

Expect plausible filler where the plan went quiet

The scope said pricing is contact only. The plan listed the tier names as an open question for the owner. The session built pricing tiers anyway, named Pilot, Site and Fleet, with band boundaries.

Nothing in that was careless. A pricing section with cards is what a marketing site looks like, so that is what got built while the answer was pending. My answer was that there are no tiers, and the commit that applied it records why the cards had to go rather than be relabelled: invented tiers implied feature gating that does not exist and price bands nobody agreed to.

The same thing happened twice more on the same page. The header carried a placeholder logo, removed so that nothing on the site implied a brand identity that had not been designed. The favicon was a letterform made up on the spot, then replaced the next morning with the application's own icon, byte for byte, because a tab on the marketing site and a tab on the app should show the same thing. The teal in the social preview image was an eyeball approximation of the brand colour, replaced with the converted value from the design tokens.

None of these are bugs a test catches. They are gaps in the plan filled with something reasonable, and reasonable is easy to read past. When a plan names an open question, check what got built in its place.

Write the findings where the next session will read them

Open the recently merged MRs in either repository and you will find no human review comments. Each has one note, from the release bot. Review happens in the session, and the findings leave it as commits whose message states the finding and how it was verified, and as issues filed before the merge. The MR template has a checkbox for the second, with the reason attached: a follow-up that lives only in an MR thread is lost work.

The next session does not read MR threads. It reads the board, the commit log and the spec. A finding in a commit body is there the next time someone touches that file. A review comment is there until the MR closes.

Decide what no rule can decide

On 18 August two sessions implemented the same small issue in the other repository, in parallel, neither aware of the other. Both worked. One added a configurable limit; the other hardcoded it. The issue note laid them side by side and recommended the configurable one. I merged the other, which had already landed, and the dropped branch's MR records what that cost: the configurable property is a fresh issue if anyone wants it.

No hook, test or guideline makes that call. Putting it in front of me with both options written out is what the setup is for.

Know what the gate cannot see

The site merged at 11:25. At 18:23 a follow-up bug merged: the landing tier had never been built. The root CI config triggers each part of the monorepo through an explicit job, and there was no job for the new one. The issue says it plainly: "branch and MR pipelines went green throughout, because a tier that is never triggered cannot go red. Nothing in the review surfaced it."

Two more things in the same fix had been copied from the sibling repository's landing site, where they were correct, into this one, where they were not: a template version pin and a missing artifact override. The scope said to mirror the sibling, and that is what happened. It still produced a config that could not fail and could not deploy.

Review reads the diff. A diff cannot show a job that is absent from a file the diff did not touch.

Sign every commit with your own name

Attribution has been off in .claude/settings.local.json since January:

.claude/settings.local.json
"attribution": { "commit": "", "pr": "" }

A commit a session wrote looks exactly like one I typed. It is held to the same standard, and if it is wrong, the name on it answers for it. Git therefore cannot say how many I typed. The session transcripts on this machine can, roughly: in August, about 60 percent of the commits on the first repository's main branch trace to a Claude Code session on this laptop, before counting the second machine.

What git does show is the merge. Since May, 383 merges across the two repositories; 327 of them carry the identity GitLab stamps when someone clicks merge in the web UI.

FAQ

Is this vibe coding? No. Vibe coding is not reading the diff. Here the typing moved to sessions and the reading moved to me. There is more reading than before, not less.

Why is reviewing agent code hard if it follows your own guidelines? Because it looks like yours. File layout, test names and commit style all match the conventions, so every surface signal says the work was already checked. The pricing tiers matched the page structure and were still wrong. A guideline can enforce the shape. Whether the content is true is what a reader checks.

Why no review comments on the MR? Findings go into commit bodies and issues, which the next session reads. MR threads are not read by anyone after the merge.

Is a day from spec to merge typical? For a bounded feature with a plan, yes. So are two review rounds after "ready" and a follow-up bug the next afternoon.

What to check in your own setup

  • For the last merge you approved, can you say why each changed file exists?
  • Where the plan left a question open, what got built in its place?
  • For each test an agent added, break the thing it guards and see whether the test goes red.
  • Where do review findings go when the session ends? If the answer is a chat window, they are gone.
  • Does your CI config have a job for the thing you just merged, or only a green pipeline?

Part two is about where this breaks. Part three is about the skills that make the spec, plan and review steps cheap enough to run on every issue.

Next Step

You Bring the Problem. We Ship the System.

One call to scope it. If it's a fit, you'll usually see working software within days. No discovery workshop, no deck.