🤖 How I Work With Coding Agents

9/5/2026 at 9:00:00 AM • ~5 min read

If you have been following along, you know that most of what I have built this year was written with coding agents rather than typed by me. I have described the products themselves elsewhere, and they are on the projects page. This post is about the part underneath them.

A coding agent with a blank prompt is a very fast junior with no memory. It doesn’t know how this repository deploys, which decisions were already settled, or that the outreach it’s about to send hasn’t been approved by anyone. Every session starts from zero and drifts a little from the last one. Almost everything below exists purely to stop that.

Thirty-two domain skills

There are thirty-two domain skills, and behind them sit roughly fourteen hundred reference documents. They are organised by domain rather than by code: engineering, design, design systems, SEO, sales, prospecting, delivery, security, infrastructure, research, marketing, media, product, planning, quality, internationalisation, and a few that are only about how I work. Each one is a folder with a short entry file, a reference/ directory holding the actual material, and an agents/ directory describing how it is exposed.

The distribution is lopsided. Marketing holds over four hundred reference documents and design around two hundred, while engineering has seventy-six and sits well down the list. Engineering is the part I already knew, so it needed the least writing down (which is either reassuring or slightly worrying, depending on the day).

Picking which one owns it

One skill exists only to pick between the others. Its own instructions say that it directs the request to the right specialised skill and doesn’t do the domain work itself.

Behind it sits a set of documents that are closer to governance than knowledge: a skill taxonomy with anti-overlap rules, a topic routing matrix for requests that cross domains, and a meta-review of where coverage is thin and when a new skill is justified. The problem those address is two skills quietly disagreeing about the same subject, with nothing telling me which one an agent actually read.

What ends up in reference

A reference/ directory fills up with a lot more than conventions once it’s allowed to hold anything.

Some of it is what you’d expect: conventions, component API rules, code review standards, deployment checklists, an anti-patterns file. Some of it is narrower. There is a document on writing whose job is to stop generated copy sounding generated, with banned phrases and a test for filler. There is an evidence standard for my own career material, where a claim that isn’t in the fact base counts as not established, which is what keeps a plausible-sounding number out of a document I have to defend.

The one I use most is a freshness registry: an owner and a cadence for every document whose contents go stale, alongside rules for checking vendor claims, pricing and fast-moving platform guidance rather than repeating what was true last year. Without it the knowledge base just keeps returning last year’s answer, and nothing about the answer shows its age.

Past mistakes are written down here as well. A colour utility appended to a base class string doesn’t override it. A check reported a page as broken when its selector had never matched anything. Each of those is a paragraph in a reference file now, paid for in full.

Questions before any code

The opening move on anything non-trivial isn’t a plan. It’s questions, put to me, before any code exists.

The mistakes that cost me time are rarely in the code. They happen in the first ten minutes, when something reasonable-looking gets built on a premise nobody bothered to check.

Plans live in the repository

Plans live in the repository as files, not in a conversation that scrolls away. A PLAN.md first, then the work split into tasks per phase. Nothing gets implemented during it, not even a helper file that seems obviously needed, because once building has started I’m reviewing a decision instead of making one.

Rules that are absolute

A handful of rules are absolute, and I arrived at each of them after something went wrong.

Nothing carrying my name reaches a third party without me. Outreach is drafted and staged, never sent, and decisions are recorded as proposals until a person accepts them. The project manager’s tool surface has no accept tool for agents at all, so the restriction does not depend on a prompt. I learned that after an agent opened a pull request on a public repository on my behalf, following something I’d said that sounded like approval and definitely wasn’t.

Database migrations never run without me asking. Batch work never runs over every user at once. It’s enqueued, capped, and pointed at an allowlist that starts with my own account, and before any batch it prints exactly which records it is about to touch.

No claim without a check

No completion claim is accepted without the check that supports it. Every session runs under a gate that re-derives the requirements from the request, inspects the diff against each one, runs the smallest relevant build or test, and reports INCOMPLETE or BLOCKED by name when something is unchecked. Anything visual needs a screenshot, because a green build has shipped a page that crashed on load more than once!

An agent will describe a fix it never verified in exactly the same confident tone as one it did. So when something comes back claimed as fixed I run the real path and read the real output: the admin table, the queue depth, the console, the response body. I check the review layer the same way, since that is also a model, and I verify its findings before acting on them.

Workflow engine, still an experiment

The part I am least sure about is the workflow engine, so I will describe it as what it is, which is an experiment I have been running rather than a finished piece of the system.

The idea is that a recurring job should not be re-planned from scratch every time. A workflow is a YAML file describing a sequence of phases, where each phase declares a goal, its inputs and outputs, the skills it draws on, a model tier, and a gate that has to pass before the next phase starts. A runtime parses one into a graph and spawns an agent per node, with the cheap tier on deterministic phases and the expensive one only where judgement is needed.

flowchart TB REQ["Request"] subgraph RUN["One workflow run"] direction TB P1["Phase 01<br>design the contract"] G1{"Gate"} P2["Phase 02<br>implement"] G2{"Gate"} P3["Phase 03<br>harden"] end SK[("Skills<br>conventions · checklists · scars")] OUT["Handoff<br>next workflow"] REQ --> P1 P1 --> G1 G1 -->|passes| P2 G1 -.->|fails| P1 P2 --> G2 G2 -->|passes| P3 G2 -.->|fails| P2 P3 --> OUT SK -.->|read by every phase| RUN
A gate is the only way out of a phase, and every phase reads from the skills.

A definition carries more metadata than I first thought it needed. The stack-selection workflow declares that it is for use when a project is committed but the stack is still open, that it does not cover starting the project or choosing hosting, and that it chains into those two afterwards. The non-goals were added because agents kept carrying on into the next two workflows unasked.

A phase itself is mostly a contract. This is one from the API workflow, abridged for readability:

contract:
  goal: >-
    Design the API contract before writing any implementation code. The
    specification is the agreement between the API and its consumers.
  gate: >-
    API specification is complete and covers all required use cases.
    Consumers have reviewed the spec and confirmed it meets their needs.
  inputs: [input.normalized]
  outputs: [phase-01-result]
evaluator:
  independent: true

The most expensive bug I have had in any of this lived here, and it was completely silent. The parser used a whitespace pattern that ate one level of indentation, so a list of actions nested under a phase collapsed into a single action. Roughly four in ten phases quietly became one task node each, which defeats the decomposition the whole design depends on. Nothing failed. Runs simply did less and did it worse. The lesson I keep relearning is that a file should be validated by the code that actually reads it, so the catalogue now has a parity test that parses every definition the way the runtime does.

I am still not sure this layer earns its keep at this size. The skills do, and I notice them every session.

Where it stands

What changed is how much ground one person covers: several products, the studio site, the internal tools and the infrastructure underneath them, with tests and deploys, from one desk.

What did not change is where the judgement sits. The agents did not decide that billing should be wired before a waitlist opens, or that a repair tool needs backpressure so it cannot take the platform down while fixing data. That is still the job, and the part I have always liked most.

Wrapping up

If the phrase AI-native engineer means anything, I think it means holding the architecture in your head, breaking work into pieces a fast and forgetful collaborator cannot slip past, and keeping the knowledge somewhere better than a prompt.

I went deeper on the skills layer in the next post. The products are on the projects page, and if you want to talk about what this looks like on a team, here is what I am looking for.

I hope you enjoyed this blog post and I will see you in the next one!

Get in touch