Agents are amplifiers. They don’t route around a weak foundation, they build on it, confidently and at speed. Whatever would mislead a new hire will mislead the agent: stale docs, sure, but just as often old code, a half-finished migration, or a pattern you’ve moved away from and not deleted.
Which is why the thing that decides the result is almost never the model. Same model, two teams, wildly different results, and the difference is the harness around it.
By harness I mean the layer between your team’s standards and the model. It’s a handful of things wrapped around it: the skills that package context, the agents that carry domain expertise, the tools it can reach over MCP and the CLI, and the hooks and CI that gate the output. Underneath all of it sit the conventions you write down.
One strong engineer with a good model is fast. A harness is how you get a whole team to that speed without dropping the floor.
I wrote a couple of months ago that AI is a channel, not a feature. The part that’s aged best is a line about controls: guardrails an AI can’t drive through, so you can move fast inside them. The model itself is close to a commodity now, and everything interesting is what you wire around it.
That harness is what decides whether a team ships robust software quickly, and it’s the bit we see done well least often. When we start with a customer, closing that gap is usually the first thing we do.
Some of what follows is scar tissue. A few of our best guardrails exist because something shipped green and broke later, and I’ll point those out as I go.
Skills: one person’s context, everyone’s default
A skill is packaged, reusable context that the model reaches for on its own. Do a job well with the agent once, write it down as a recipe, and the whole team can run it.
On Skipper, the internal platform we’re building to run a consultancy from lead to invoice, the workhorse is a development-session skill. It pins the role, a fixed six-step workflow and the conventions we treat as non-negotiable, and it’s more than eight in ten of all our skill calls, so a session runs the same way whoever starts it.
Around it sit tighter ones. A code-review, simplify and verify trio for quality. An architecture-health scan that grades the codebase before and after a session, and a design audit that triggers on symptoms like “users keep missing the submit button”.
The team point is the whole point. Skills are distributed centrally so everyone gets them, they trigger automatically rather than waiting for someone senior to remember, and they point at a single source of truth so they can’t drift into stale forks. The standard stops being folklore and becomes a default.
Agents: build in the argument
Last time I argued that the highest-value thing you can do with a model is refuse to let it agree with you. Back then that was a habit you practised each session. Now it’s a checked-in asset.
Skipper has two domain-authority agents, one for finance and one for resourcing. Each is the team’s hard-won expertise written down and cited to the exact file and line: the money model to the penny, the resourcing rules in full. They’re read-only by construction, so they advise but can’t touch the ledger.
What that changes is my job. I’m not handing work to an agent and hoping, I’m building alongside a domain expert who’s always on call, who I can interrogate mid-flow, and who’s told to push back rather than agree. Both are told, in as many words, that they’re not a cheerleader and not a rubber stamp, and to treat memory and prior belief as leads to verify, not facts.
Code is truth; this brief is the map.
That line is from the finance agent’s own instructions. The expertise that used to live in one head, and bottleneck on one calendar, is now something the whole team builds with. There are two so far, both read-only, and that’s deliberate.
Tools: what the model can touch
Skills and context decide what the model knows. Tools decide what it can do. This is the part people skip: the harness is also the MCP servers it can call and the CLI commands it’s allowed to run, and how tightly each one is scoped.
On the Skipper build there are six live connectors, and every leash is deliberate. Linear can read and write issues, Obsidian is scoped to the docs folder only, and Context7 pulls library documentation read-only. A code-health tool can look but never mutates, the review app can comment but not merge, and browser control is gated per site.
There’s one deliberate default too. Skipper’s own product connector is off by default, so an agent building the product can’t reach live product data on its own. An engineer wires it in by hand when it’s genuinely useful, usually to troubleshoot something, then takes it back out.
None of this is broad access. Every tool is one narrow, named permission on a single system, and those limits are written down where anyone can read them. Being able to see exactly what an agent can and can’t touch is what earns trust, from the team now and from an auditor later.
Hooks and CI: make the wrong thing hard to do
This is the load-bearing part, and where most teams underinvest.
Hooks let you shift validation left and catch problems earlier. We use them across several of our repos, including the site you’re reading this on, where a hook runs our checks before a pull request can even be opened, so a broken internal link or a dropped Lighthouse score gets caught at the source rather than in review.
Skipper is more complex, and today it takes a different route, with the guardrails living in git, the build and CI, and a pre-push hook catching the obvious traps first. Where to lean on hooks is a line we’re always re-assessing, repo by repo; it’s a question of your tech and your team, not a rule.
Enforcement really lives in CI. Every Skipper pull request runs the same gates, and a boundary checker of around fifteen hundred lines fails the build on what we’ve decided is never allowed: one domain importing another, a cross-domain database join, or money computed in floating point on the billing path.
The tests run against a real Postgres database rather than mocks, roughly four thousand of them, and the same run lints the code and scans it for known vulnerabilities. I learned one edge of that the hard way: real databases in Docker leave real volumes behind, and one filled disk later I clear the old ones down religiously.
A green check should mean the rules held.
The reason that matters is that the same gates run whether a human or an agent wrote the code. No gate knows the difference, and it shouldn’t. Speed comes from letting people and agents move fast, safety comes from the gates they both have to clear.

There’s a catch, and it’s an obvious one once you’re living it. When work ships in hours instead of days, the bottleneck doesn’t vanish, it moves to review and coordination. Agents generate faster than humans can check, so review capacity becomes the real constraint.
Our answer is to move as much of that review left as we can, before a change ever reaches a person. All of our work runs on Opus at max effort with dynamic workflows enabled, so a change is peer-reviewed and fixed inside the agent loop, left of CI, before it comes back to the developer.
It’s also why we built Overwatch, an automated critique layer that pairs security analysis with a codebase-maturity tool we call Groundtruth. It’s gone well beyond what we used to get from human-led peer review, and we’ll write about it properly soon.
Now the scar tissue on the gates themselves, because we get plenty wrong. When something breaks we take two actions, not one: we fix it, and we add a deterministic check so the same mistake can’t ship again unnoticed.
A production outage taught us to couple every log event to an alarm. A filter that didn’t filter shipped green, so a control like that now needs a test that proves it works. The harness learns from incidents, it doesn’t pretend to prevent them all.
The standard, written down
The point is simple. A team agrees, once, on how it builds, and then makes that agreement executable.
On Skipper the module boundaries are non-negotiable, and every pull request has to respect them. The spec, the code and the migrations move together as one versioned source of truth. A human still owns the merge, but nothing ships on vibes: quality is judged by comprehensive testing for correctness, performance and security, not by a person skim-reading the diff.
None of that relies on anyone remembering it. The wrong thing doesn’t compile.
This is what we mean now when we talk about setting a standard for how we build. Not a wiki page nobody reads, but a harness the work has to pass through.
Where the human still sits
“The wrong thing doesn’t compile” is only half the story. The gates stop the wrong implementation. They can’t stop you building the wrong thing.
Hooks, tests and boundary checks make a badly built change hard to ship, but none of them can tell you whether you built the right thing in the first place. A feature can be beautifully engineered, fully green, and still solve a problem nobody had. That failure lives upstream of the code, and no pipeline catches it.
That’s where the human stays essential, and it’s worth being precise about how. On Skipper we don’t gate quality with a person reading the diff line by line; the code is reviewed adversarially by agents told to break each other’s work, then held up by unit and end-to-end tests and by Overwatch. The human’s job is the part none of that can do: deciding the ask is right, judging the result against intent, and owning the merge.
That balance is a choice, not a rule. On plenty of builds a human reading the code is still right, and we do it; on Skipper that critique comes from adversarial agents, testing and Overwatch instead, and the human moves up to judgment and accountability. Agents amplify whatever you asked for, so being sure you asked for the right thing is the job that never automates.
The litmus test
Here’s the bar we hold ourselves to: a new engineer, or a fresh agent session, picks up a ticket, builds the feature, and it comes back usable and ready for testing the first time. That sounds almost magical. It isn’t, and it’s the clearest signal that the harness is doing its job.
The git history is the closest proxy we have. Since May, more than a thousand pull requests have merged to Skipper’s main, over four hundred in the last month, and effectively none have been reverted.
Plenty of choices compound to get there, and some sit further upstream than you’d expect. Language and tooling matter more than people admit, because a stack that’s simple and idiomatic is the kind of code a model handles naturally. It’s a big part of why we reach for Go over Python on a lot of our work, and Astro over a heavier framework for a site like this, each of which probably deserves its own post.
What to try
The scar tissue, boiled down to what we now do.
- Fix the foundation before you scale the agents. Stale docs and old code both mislead an agent, and mess compounds faster than value. The foundations come first.
- Scope every tool tightly, and write the scopes down. Legible access is what earns trust. Specific verbs on specific systems, nothing broad by default.
- Demand evidence with every output. Tests, diffs, screenshots, or it didn’t happen. A confident summary isn’t proof.
- Size review capacity like it’s the constraint. Because it is now. Plan the human review around the pace the agents actually set.
- Capture every win as a skill, and every mistake as a check. Don’t just fix an issue, add deterministic validation so it can’t recur unnoticed. The harness should be better every Friday than it was on Monday.
- Verify the ask, not just the output. A guardrail catches a bad build, not the wrong thing. Check the intent up front, and have a human read the result against it.
None of this is finished, and it changes monthly, but staying ready to re-learn is the job, not a disclaimer on it. The direction is clear enough to commit to: put your effort into the harness, not just the model. That’s the standard we’re building to.