Onboarding for coding agents
July 29, 2025
I've been experimenting with coding agents - Claude Code, Cursor, Codex, Jules, and others.
They're all impressive, but also limited by how much context you give them, and they each want their context in different places.
Cursor uses .cursor/rules
, Claude Code looks for CLAUDE.md
, Codex and Jules want AGENTS.md
(and there are .windsurfrules
, .clinerules
, .github/copilot-instructions.md
...)
I used to put hundreds of lines of context in tool-specific formats like CLAUDE.md
, but lately I've been experimenting with a simpler approach:
- Put context in READMEs (universal and tool-agnostic)
- Put constraints in the environment via tools (type checkers, linters, formatters, tests)
My CLAUDE.md
went from hundreds of lines to just 13.
Put context in READMEs
READMEs have worked well for 50 years as a universal, tool-agnostic format for project context -- already familiar to every developer.
So I've been moving context out of tool-specific files and into READMEs instead.
But instead of cramming everything into one long README, I use a simple naming convention to create composable context for different domains:
README.md
- A high-level overview (for the project or a package/module)README.<domain>.md
- Focused context for a specific domain or purpose
For example, my README.architecture.md
might explain:
- How the app is structured
- Key architectural decisions
- How data flows between client and server
- Which patterns to follow when adding new features
Others I've found useful:
README.commands.md
- Key development commands and scriptsREADME.design.md
- Design system, components, visual guidelinesREADME.testing.md
- Testing patterns and strategies
📚 Onboarding
This simple convention keeps my context more modular and DRY (Don't Repeat Yourself).
But which READMEs should I write?
My mental model is to think of context as onboarding for both human teammates and AI tools.
Ask yourself: if a new software engineer or designer joined this project tomorrow, what would you want them to read before they start on their first task? That's the type of context you should put in READMEs.
The key point is that every new Cursor or Claude Code session is like a new teammate joining the project with zero context. If you don't first get them up to speed, how will they do a good job on the tasks you give them?
So now I've replaced hundreds of lines of context in my CLAUDE.md
file with a few "onboarding" instructions:
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## 📚 Onboarding
At the start of each session, read:
1. Any `**/README.md` docs across the project
2. Any `**/README.*.md` docs across the project
The **
wildcard here will match files in any subdirectories, not just the root folder.
Now that context is in READMEs, it's easy to reuse it across multiple tools. However AI coding tools evolve in the future, I expect clear written communication will always be valuable.
✅ Quality gates
Onboarding helps AI tools get up to speed, but how do we ensure they write quality code?
I used to list various rules and coding preferences in .cursorrules
or CLAUDE.md
files.
But now my goal is to encode as many constraints as possible in the environment, via tools rather than prompts.
I call these "Quality Gates" - it's whatever checks you'd want to run before a new engineer pushes to production.
Here's a recent example from a NextJS/TypeScript project:
## ✅ Quality Gates
When writing code, Claude must not finish until all of these succeed:
1. `pnpm type-check`
2. `pnpm format`
3. `pnpm lint`
4. All unit tests (`pnpm test:run`) pass
If any check fails, fix the issues and run checks again.
This works well because LLMs are terrible at formatting whitespace or sorting imports and Tailwind classes consistently, or ensuring every React hook's dependency array is correct. But they're good at running tools and fixing errors until all checks pass.
The specific gates depend on your stack - eg ESLint/Prettier in TypeScript, ruff/pytest in Python, or go fmt/vet/test in Go. The key is to load up constraints, and make them strict.
With these two sections (📚 Onboarding and ✅ Quality Gates), my entire CLAUDE.md
file is now 13 lines.
Software gets an OODA loop
Why does this Quality Gates pattern suddenly work so well?
It didn't work a year ago, but newer models (like Sonnet 4) and tools (like Claude Code) mean coding agents can now iterate for minutes or even hours until all specified constraints pass.
Zooming out, this feels like a deeper shift: coding agents can now run their own OODA loop (Observe, Orient, Decide, Act). Instead of just executing instructions or predicting tokens, they can observe outcomes and adapt to feedback from their environment.
When Claude writes code, it sees type errors and fixes them. It runs linters and adjusts. It works in a loop until all constraints pass - similar to how a junior engineer would use IDE or compiler feedback to fix mistakes.
Humans have been tool builders for thousands of years, but we've always operated the OODA loop ourselves. Now we're building tools with their own primitive OODA loops.
I have mixed feelings about this.
As an optimist, I feel more leverage and agency as a builder than ever before, as I can delegate increasingly complex tasks to AI tools.
But I also worry about what happens if we remove ourselves from the loop entirely, when our tools can pursue complex goals on their own.
Today the AI OODA loop works best in software engineering, but I suspect similar Quality Gates could work in other domains where it's possible to verify outputs.
Define the laws of physics
"Vibe coding" (where AI handles implementation while you focus on outcomes) is very fun and fast.
But without good constraints, it's easy to make a mess.
So here's my rule: I never let AI vibe code my environment.
I define the laws of physics - the tech stack, components, libraries, database, deployment setup, design system, etc. These can be expensive to change later, and they define many of a project's constraints. Then I let AI work within those constraints.
When I need a new library, I'll ask Claude for options and trade-offs, but I always make the choice myself after poking around docs. A bad dependency choice can derail a project, while solid abstractions are a joy to build on.
Strict laws of physics give me more confidence in what AI tools are doing, and make code review much easier. I think they also help with speed, as I never want to waste time reviewing or testing half-baked AI code before every constraint passes.
What's next?
I'm still experimenting, but the idea is simple: put context in READMEs, constraints in the environment via tools.
I'm curious what other builders are putting in files like CLAUDE.md
or AGENTS.md
?
If you've found any good patterns, I'd love to hear about them.
In future posts, I'll be exploring other aspects of "fuzzy" computing. In particular, how might we leverage LLMs to generate READMEs or design systems, and keep them up to date as a project evolves? Get updates if you'd like to follow along.