Writing

Keep an Authoritative Reference Library Your AI Follows in Every Project

Keep an Authoritative Reference Library Your AI Follows in Every Project - abstract illustration

An AI coding assistant left to its own judgment writes the average of everything it has ever seen. That average is generic. It's not how you name things, not how you structure a service, not the library you standardized on three years ago. The model doesn't know your way exists unless you hand it your way and tell it to follow it in every project.

I run 10 live products across a few stacks: Java on Spring Boot, Angular front ends, a CMS layer, and native Apple apps. The only reason an AI produces code that fits those codebases instead of code that fits a tutorial is a maintained reference library, and a per-project instruction file in each repo that points at it. This is the piece most people skip, and it's the difference between an assistant that reinforces your standards and one that quietly erodes them.

Why the Default Is Generic

A model has no memory of your last session and no access to your unstated preferences. When you ask it to write a repository class, it reaches for the most statistically common pattern in its training data. That pattern is a blend of every blog post, every Stack Overflow answer, and every open-source repo it ingested. It's competent and it's average.

Average is the problem. Your codebase has decisions baked into it: a builder pattern you use everywhere, a specific way you annotate storage fields, a query style your team reads fluently. None of that's the internet default. So the AI, working from the default, produces code that's technically fine and locally wrong. It compiles, it passes a casual review, and it drifts your codebase one commit at a time toward a generic mean you spent years moving away from.

You can't fix this with a better one-off prompt. You fix it by giving the model your references and making sure it reads them before it writes anything.

What Belongs in the Library

The library is the set of documents that encode how you actually build. Mine breaks into a few kinds of content:

Coding conventions. The canonical patterns for a stack, written as rules the AI can follow literally. For my Java work this is an ai-rules-library of the Klass framework conventions: the builder pattern, the storage annotations, the ORM query style. These are not aspirational style guides. They're "this is how we write a class, here is a correct example, follow it."

Architectural and how-we-do-X patterns. The repeated shapes in your system that a new class needs to match: how a service is layered, how errors propagate, how you wire a scheduled job, how a data-parsing pipeline is structured. Anything where there's a right answer specific to your system and a dozen plausible wrong ones.

Naming. Boring and high-leverage. Table prefixes, ID formats, file and folder naming, the difference between what you call a "contact" and a "lead." Naming drift is the fastest way to make a codebase feel like it was written by ten different people, and it's trivially preventable with a written rule.

Canonical facts and numbers. A single source for the fixed values that show up across your work so the AI never guesses or invents them. In my vault this is a canonical-facts note: the year I started (1996), the count of live products, the size of the MCP server. When those numbers only live in your head, every document that cites them is a chance for the model to make one up.

Per-stack patterns-and-gotchas guides. For each stack, a guide covering the patterns that work and the traps that don't. This is important enough that I gave it its own post: keep a gotchas file your AI reads before it repeats your mistakes. The gotchas are the hard-won half of the library, the failures you already paid for once.

Organize by Stack and Domain

A single flat pile of rules doesn't scale, and it wastes context. If your Java rules and your Angular rules and your Apple rules are all in one file, every project loads all of them, most of which are irrelevant. Split the library by the thing it describes.

My project docs live in one folder, ai-project-docs, subdivided by stack: java/, angular/, cms/, apple-native/. Each stack folder has a map file that names the topic files under it and says when to read each one. The Apple folder, for example, starts with an apple-native-app.md overview that links out to the SwiftData file, the concurrency file, the sandbox and security-scoped bookmark file, and the macOS-specific gotcha set. A model working on an Apple app reads the map, then pulls only the topic files relevant to the task.

The organizing principle is that the reader (human or model) should be able to answer "where do the rules for X live" in one hop. By stack at the top, by topic underneath. When you have a shared team, this same library belongs in a git repo the whole team owns rather than scattered across individual machines.

Point Every Project at It

A library nobody reads is decoration. The mechanism that makes it load is a per-project instruction file in the repo root, the CLAUDE.md pattern. This file is the first thing the AI reads when it opens the project, and its main job is to say: here's what this repo is, and here are the authoritative references you must consult before working on it.

The instruction file doesn't restate the rules. It points at them. A Java service repo's file says, in effect: this is a Spring Boot service in the Klass framework; before writing code, read the Java coding conventions in the rules library and the relevant patterns-and-gotchas doc under ai-project-docs/java/. When I change code that one of those docs describes, I update the doc, so the pointer never goes stale.

Two rules make this reliable:

  1. Every repo has an instruction file, even a one-line one. A repo without it gets the generic default, which is exactly the outcome the library exists to prevent.
  2. The instruction file references the shared library rather than copying from it. The moment you paste rules into a project file, you've forked them, and the copy rots the first time you update the original.

This is one instance of a larger point I make in give your AI the context it needs: the model sees far less of your world than you assume, and the instruction file is where you close that gap on purpose.

One Authoritative Source Beats Tribal Knowledge

The reason to centralize is that the alternative is knowledge scattered across people's heads, old Slack threads, and the implicit conventions of whichever file the AI happened to read. Scattered knowledge has no version, no owner, and no way to be consulted deterministically. Two engineers get two answers. The AI gets a third.

One authoritative source fixes the failure modes at once. There's a single place to update when a convention changes, so the whole fleet of projects and every AI session picks up the change the next time it reads. There's a single place to point new work at, human or model. And there's a single place to audit when the output starts drifting, because you can read the rule the AI was supposed to follow and see whether the rule is wrong or the AI ignored it.

It also compounds. Every gotcha you write down is one you never have to rediscover. Every convention you encode is one the AI stops getting wrong. The library is the mechanism by which a lesson learned once becomes a lesson applied everywhere, instead of a lesson you re-teach every time you open a new chat.

Keeping it current is real work; a reference doc that describes last year's architecture is worse than none, because the AI will follow it confidently into the wrong pattern. The rule I hold to is simple: when I change code that a doc describes, I change the doc in the same pass. The library is only authoritative for as long as it's true.

Building something like this?

This is the kind of work I do for clients. Tell me what you're building and I'll give you a straight read on the approach.

Book a 30-minute call