How I built an agent system that actually knows my codebase
A guide to setting up Cursor agents with rules, commands, and a knowledge base, so they stop guessing and start working from your actual patterns.
Most people use Cursor like a smarter autocomplete. You write some code, it suggests the next line, you accept or reject. That works. But it's not the interesting part.
When the agent knows your codebase well enough to make the right call without you explaining context every time, something shifts. That's what I spent a week building.
The problem with default agent setups is that they work from the nearest file. Whatever is closest in the repo becomes the pattern. In a mature codebase that's usually the oldest file, written before the conventions existed. So the agent confidently spreads patterns you've been trying to phase out.
The fix is giving the agent explicit rules that describe what you actually want, triggered by the files being touched.
The three layers: rules, commands, and knowledge
There are three layers to a setup that works.
Rules are the coding standards. Each one is a .mdc file with a YAML header that specifies which file paths trigger it. Touch a Redux file, get the Redux rules. Touch a form component, get the form rules. Two rules are always active regardless: one for project-wide standards and one that checks documentation after any feature change. Everything else is path-triggered so the context stays relevant and small.
Commands are the workflows. One primary command handles the full lifecycle of a ticket: intake from Jira, map the affected files and load the matching rules, plan without touching code until approved, build following only what was loaded, verify with a cleanup checklist, close with a documentation check. The planning phase is the most important part. The agent lists what it will touch and which rules it loaded before writing a single line. That's where you catch misunderstandings cheaply.
Knowledge is the harder part. Rules describe how to write code. Knowledge describes what the codebase actually contains: every menu feature, every route, the layer each component belongs to. Right now this lives in YAML registries and Confluence mirrors. The registries were generated by having the agent scan the menu reducer, the sidebar component, and the pages directory. Fifty-seven features across eight modules, mapped once, referenced forever. Confluence is where it's readable by people, but that's an implementation detail. The point is that the knowledge exists somewhere the agent can reach, verbatim, not summarized.
Summaries are the failure mode. An agent reading a three-line phase summary instead of the full 148-line command file will do the wrong thing confidently. Exact mirrors from day one, no exceptions. Where the knowledge lives matters less than the fact that it's complete.
The rule routing table is what makes it non-generic
The rule routing table is what makes the whole thing non-generic. It lives in the standards file and tells the agent exactly which rules to load based on what files are touched. Redux touched, load Redux rules. Service layer touched, load service rules. Menu feature changed, load the documentation sync rule. Without this the agent loads everything or nothing and the results are inconsistent.
One practical side effect: path-triggered rules keep the context window small. The agent loads only what's relevant to the files being touched. Tested in production and it makes a measurable difference on token usage.
What I got wrong the first time
A few things I got wrong the first time.
Don't copy rules from another project. I had a setup on a different codebase and the temptation to paste it was strong. The two projects use different routing, different component organization, different layer names. Rules written from the wrong codebase get followed confidently and produce wrong output. Explore the actual codebase first, write rules from what's there.
Don't use Confluence page IDs from another project. Silent failure: the agent fetches context for the wrong codebase and never tells you. Each project needs its own namespace.
Don't let legacy code be the nearest neighbor. In any mature codebase the oldest files violate every convention you care about. Rules need to explicitly say which patterns are legacy and what to use instead. Otherwise the agent treats the oldest file as the target.
What the finished setup does
The result is an agent that can take a Jira ticket, map the affected files, load the right rules, write a plan you can review, implement it following your actual patterns, and check its own work. Not always perfectly, but consistently enough that the failures are predictable and catchable at the plan stage rather than after the code is written.
The knowledge layer is still evolving. Confluence works but it's not the final answer. The ideal is something the agent can query directly from the repo without a sync step. That's a problem for later. The architecture holds regardless of where the knowledge lives.