Back to Portfolio
ArticleTechnologyJul 15, 2026

AI Workflows That Don't Rot Your Codebase

Event
The Innovation Lab
Overview

AI is leverage only inside a disciplined loop — plan, devil's-advocate, execute, post-mortem, improve your skills. Let it push ahead unsupervised and the same tool quietly wrecks the project: drifting to mimic old code, writing docs that pass typecheck but lie, leaving half-refactors and parallel types behind. A field guide to the loop that ships and the anti-patterns that sink, with downloadable skills and a real brand-book deliverable.

Technologies
AIWorkflowsAgentsAnti-PatternsSkillsPost-Mortem
AI Workflows That Don't Rot Your Codebase preview
§ 01The Thesis

The same agent is a force multiplier or a wrecking ball. The difference is the loop around it.

Autocomplete is not a workflow. The workflow is the discipline: plan it, attack the plan, execute in isolation, dissect what happened, and fold the lesson back into your tools.

01

The loop is the product

The value isn't the code the agent types — it's the repeatable loop that holds quality steady as volume climbs.

02

Unsupervised is entropy

Left to push ahead, an agent optimizes for looking done — mimicking nearby code, writing confident-but-wrong docs, stacking half-refactors.

03

Skills compound

Every post-mortem folds a lesson back into project-local skills, so the next run starts smarter. Tools that never update rot.

First the loop. Then the ways it breaks. Then the deliverables it produces.

§ 02The Good Pattern

Plan, attack, execute, dissect, improve.

Discipline is a cycle, not a checklist. The plan feeds the critic, the critic hardens the plan, execution proves it, the post-mortem reads the run, and every lesson folds back into the tools before the loop turns again.

The AI workflow loop: plan, devil’s-advocate, execute, post-mortem, improve skills12345
01

Plan

A machine-executable, wave-structured plan — not prose. Each task carries its files, a verbatim canonical code pattern, a forbidden list, its dependencies, and its acceptance criteria.

02

Devil's-advocate

A rigorous critic — not a contrarian — attacks the plan before a human ever sees it. Does each task achieve its goal? Is there a scope-versus-ambition gap? Was a shared file edited without listing every consumer?

03

Execute

Run the plan as file-disjoint parallel waves inside an isolated worktree. A central gate — lint, then typecheck, then test — runs between waves. The main checkout is never touched.

04

Post-mortem

An orchestration retrospective, not a code review. Where did the process churn, and why?

05

Improve skills

Fold each lesson back into your project-local skills so they can't rot. Apply the edits, don't park them.

The plan is a contract, not a suggestion — because the executor parses it mechanically.

What a machine-executable task looks like — no prose to interpret.
Task: add-rate-limit
Files:
  - src/services/RateLimiter.ts
Pattern:
  export const makeRateLimiter = (limit: number) =>
    Effect.gen(function* () {
      const used = yield* Ref.make(0)
      return {
        take: Effect.gen(function* () {
          const n = yield* Ref.getAndUpdate(used, (count) => count + 1)
          if (n >= limit) return yield* new RateLimitError()
        }),
      }
    })
Do not:
  - as-casts (as, as const, as unknown as) or ! assertions
  - parallel type definitions — types flow from the schema
  - Effect.fail(new ...) — yield the tagged error instead
Acceptance:
  - requests over the cap return 429
  - a property test drives the limiter
§ 03The Failure Catalog

Every one is the agent optimizing for appearing finished.

Each failure below is the same instinct wearing a different mask: the agent races toward something that looks done. Naming the mechanism is how you build the guardrail.

01

Drift to mimic the codebase

Left to its own judgment, the agent ignores your plan and pattern-matches whatever surrounds the edit — so one bad local convention metastasizes across every file it touches.

FixInline the blessed pattern verbatim into the task, and tell the agent it outranks the neighbouring code.

The cost of a long plan is paid once; the cost of a wrong plan every time the agent drifts.

02

Docs that pass typecheck but lie

Types go green after a rename or a behaviour change while every doc describing the old path is now false. Stale docs are worse than none — they actively mislead the next agent.

FixSweep the whole repo keyed on the old name or behaviour, and verify a fact is actually false before you delete it.

03

Half-refactors & parallel types

Removing a cast by hand-writing a parallel type when a canonical one already exists is half a fix — the duplicate will drift. Adding a field to a hand-duplicated shape is a STOP signal, not a checklist item.

FixConsolidate to one source-of-truth type first, before anything new is built on top of it.

More building means more to refactor — you can't let it push ahead.

04

Context pollution — misc docs everywhere

Deep design notes inlined into always-loaded context, or scattered across the tree, drown the signal. The agent reads the noise and drifts.

FixKeep the top-level guide a thin index; quarantine depth into a docs folder and reference it. One task, one job, one small context.

05

The "looks done" trap

Compiling and passing unit tests is not done. A large share of real bugs compiled and unit-passed, then broke on deploy where it counted.

FixAdd a gate the agent can't skip — integration and visual verification before anything is called done.

§ 04Workspace Hygiene

One task, one worktree, no side quests.

Parallelism is only safe when the agents can’t step on each other. That safety isn’t a scheduling trick — it’s an isolation property you design in before a single subagent runs.

01

One task per subagent

Each agent gets exactly one task and is told so — hard file boundaries, no side quests. A bounded agent is a predictable one.

02

File-disjoint waves

No two tasks in a wave touch the same file; a shared file forces a wave split. That single invariant is what makes parallelism safe.

03

Isolated worktrees

Every task runs in its own git worktree off the base branch. The shared checkout is never switched — doing so corrupts every sibling agent mid-task.

04

No whole-tree ops

A tree-wide reset, add-all, or repo-wide formatter wipes siblings' uncommitted work. Agents lint only their own paths; the authoritative gate runs centrally, between waves.

05

Don't feed it the world

More context is not better. A subagent buried in miscellaneous docs drifts. Give it the task, the pattern, the forbidden list — nothing else.

A plan is sliced into waves where every task in a wave edits a distinct file.
Wave 1  (parallel — every task edits a distinct file)
  task A -> src/pages/overview.tsx
  task B -> src/pages/loop.tsx
  task C -> public/skills/planning.md
Wave 2  (depends on Wave 1)
  task D -> src/pages/index.tsx   # imports A + B

This is the operational face of the same principle: you can’t let it push ahead — you fence it in so the one move available to it is the right one.

§ 05Why Local

A skill only learns if it lives with the project.

The loop’s last move folds each post-mortem’s lesson back into your skills. But those lessons are project-specific — the exact command that proves a deploy, the driver that only loads under one runtime, what “done” actually means here. Keep the skills global and there’s nowhere for any of it to go.

planning-skill.mdlessons folded in · 60+
  • The data driver only loads under the production runtime — unit tests must stub it; verify the real one live.
  • Reading a background job's storage needs the remote flag, or it reports empty and looks like the write failed.
  • “Done” is a row in the datastore, not an entry in the third-party dashboard — staging mocks the call.
  • This build breaks only inside the container's module layout; the bare build passes clean.
  • One line's order in the server config is load-bearing — reorder it and the guard silently stops firing.
  • Ban the cast a parallel type was hiding — delete the duplicate, not just the symptom.
… and dozens more — one for every time the loop ran.

The count is a proxy for how many times you’ve run the loop. A fresh generic skill carries none of it.

Every project's facts are its own

Two projects on the very same stack still disagree on the details that decide a change — which data client, whether CI even runs on this branch, what a deploy actually touches. A skill built to serve both is wrong for each. The stack is fixed, so there's nothing to detect — it's baked in.

Gotchas are scar tissue

None of these are in the framework docs. Each was learned by getting burned once, in this codebase, and written down. A generic skill would have to rediscover every one; the local skill just knows.

A generic skill can’t rot — but it can’t grow either. A local one does both, and only the growth compounds.

§ 06Make It Yours

Skills are the compounding asset.

The loop only compounds if the tools improve. Keep skills project-local and let the post-mortem edit them in place after every run — this is the loop that keeps them from rotting. Pull latest before you branch, or you’ll reproduce a bug a newer skill already forbids.

Wire in your own commands, base branch, and forbidden list.

§ 07The Deliverable

The workflow ships artifacts, not just commits.

The same disciplined loop produces client-facing deliverables — a brand book, a spec, a report — compiled the way code is: from a template, in a text source, reproducibly, versioned. Below is a real example generated for this very site’s brand.

Brand guidelines cover page
§Cover
Brand guidelines colour palette page
§Palette
Brand guidelines voice and tone page
§Voice

Text in, PDF out — the deliverable is code, so it gets the same discipline.

Download the 12-page PDF
§ 08The Takeaway

Fence it in, and it flies.

Point an agent at a problem with no fence around it and its default failure mode is the anti-patterns: it drifts from the plan, writes docs that lie, and leaves half-refactors in its wake. The disciplined loop — plan the work, argue against the plan, execute in isolation, run the post-mortem, and fold the lesson back into the skills — is what converts raw capability into durable leverage.

The discipline is the moat, not the model.

See more work

Ready to transform your engineering?

Whether you need technical leadership, enterprise development, or team optimization—let's discuss how we can help.