I stopped reviewing my own code. Here's what had to be true first. A developer who runs multiple coding agents in parallel now merges pull requests without reading the diff, having moved code review checks to earlier stages. They enforce strict linting rules as errors, centralize exceptions in config files with reasons, and extract decisions into tested pure functions. The approach eliminates the social cost of strict rules because agents don't get annoyed, and CI runs on multiple platforms to catch issues. Most days now, I merge pull requests without reading the diff. That sentence used to describe someone I would not have hired. So let me be precise about what changed, because it isn't confidence and it isn't recklessness. It's that I moved the things review was catching to somewhere that catches them earlier. Here's the honest version of how that happened. I run several coding agents in parallel. That produces more diff per day than I can read. Not "more than I feel like reading" — genuinely more than fits in a working day. When that happens you have exactly two options: I picked the second one. Not because I'm brave, but because option 1 means throwing away the reason I set this up. The uncomfortable part: option 2 is not a mindset. It's a list of specific things that have to be true. Here's mine. Every code review I've ever done, the majority of my comments were mechanical. This function is too long. This nesting is too deep. Why is this any? Machines can say all of that. So I made them say it, as errors : "max-lines-per-function": "error", { max: 60, skipBlankLines: true } , complexity: "error", 20 , "max-depth": "error", 4 , "max-nested-callbacks": "error", 4 , Plus eslint-plugin-sonarjs with cognitive-complexity as an error, and @typescript-eslint 's strict preset — any banned, non-null assertions banned. Nothing here is novel. What's different is the next part. This is the part I find genuinely interesting. If you put those thresholds on a human team, you get a PR relaxing them within a week. Not because engineers are lazy — because "this function is 63 lines and splitting it makes it worse" is sometimes true , and arguing about it every time is exhausting. Lint strictness has always been a trade-off between machine correctness and human patience . And loosening the rules was never really a technical decision. It was a social one. An agent doesn't get annoyed. It reads the rule, splits the function, moves on. It has no opinion about being told to do it again tomorrow. So the social cost went to zero, and once that happens the trade-off only tips one way. I turned everything up until it hurt, and nobody complained, because nobody was there to complain. The moment rules get strict, real exceptions appear. If you allow // eslint-disable-next-line , the rules are dead within a month — that comment is invisible in review and permanent in practice. So exceptions go in the config file, one line per reason : files: "src/components/Sidebar.vue", // @keyframes — the "thinking" spinner ring "src/components/GuiPanel.vue", // .frame + .frame sibling-combinator spacing "src/components/FilesOverlay.vue", // :deep into CodeMirror's injected root , rules: { "vue/no-restricted-block": "off" }, Every entry says why . And the comment above the block says: delete the entry when the reason goes away. The difference is visibility. An inline disable is invisible. A growing allowlist in a config file is a thing you can look at and be embarrassed by . This is the part most setups skip. If a rule decides something — which file extension goes where, how a path is normalised, what counts as a valid session id — that decision is code , and code that is only exercised through a UI is code nobody tests. So decisions get pulled out into pure functions in a shared module, and those functions get tested against the awkward cases: empty, null, boundary, wrong-cased, wrong-platform. That project currently has a few thousand test cases, and the vast majority are testing small pure functions rather than flows. The point is not the count. The point is: when the rule is a pure function, the rule can be tested. When it's embedded in a component, it can only be reviewed. And I stopped reviewing. Our whole team is on macOS. Our users are not. So CI runs Linux and macOS on every PR, and Windows on a nightly schedule it's slow, and daily is enough to catch drift . This one paid for itself immediately, and not in the way I expected. It's the only environment where I can reproduce a Windows bug report at all. Before, a Windows issue meant asking the reporter to test my guesses. Now I push a branch. We also write Windows-specific test cases deliberately — path separators, realpathSync behaviour, fs.watch differences — so that fixing one doesn't quietly break the others. Claude Code writes. Then Codex reviews , and CodeRabbit reviews, and the loop runs until they stop objecting. The mechanism that matters here isn't "AI review is good." It's that the writer and the reader are different models. A model reviewing its own output shares its own blind spots. Two different ones don't, mostly. This is the closest thing to a replacement for what I stopped doing. It isn't as good as a careful human reviewer. It is much better than a tired human reviewer at 11pm on the fortieth PR of the day, which was the realistic alternative. I want to be honest about the boundary, because "I don't review anything" would be a lie: Everything else, I let through on green. Three things I'd want to know if I were reading this skeptically: It front-loads a lot of work. None of the six items above is free. If you set up two of them and stop, you have strictness without a safety net, which is worse than neither. It only works if the stack is uniform. The reason my per-repo config files are nearly empty is that every project uses the same language, the same test runner, the same CI shape. If your repos disagree with each other, you'll be writing the same rules over and over. Fix that first; it's cheaper. Speed is not correctness. Things do get shipped fast and fixed fast. What this setup buys is not "no bugs" — it's that the bugs that survive are the ones review wouldn't have caught either. I set all this up to save time, and it did. But that isn't the interesting part. The interesting part is that lint strictness, test coverage, CI breadth — the whole category of "engineering discipline we know we should do but don't" — was never really blocked on knowing better. It was blocked on how much friction a human team will absorb before it starts negotiating. That constraint just got removed. Not gradually. It's gone. I don't think most of us have updated for that yet. Everything above runs in the open: my global config and the project it runs on, both MIT. Copy whatever's useful.