Boilerplate vs Project-Specific Code from a Model
A language model asked for a sorting function will often return something strange: a fully-formed utility with a docstring, three optional parameters, and a generic name like processItems. The code compiles. It handles edge cases nobody asked about. It also has almost nothing to do with the project it was dropped into. That gap between the plausible and the particular is where most of the real work with these models now lives.
The distinction worth drawing is between boilerplate and project-specific code. Boilerplate is the scaffolding any competent developer could write from memory: a config loader, a retry wrapper, a migration stub, a test fixture. Project-specific code encodes decisions only this codebase has made. A model is genuinely good at the first category and quietly dangerous in the second, and telling them apart is the skill that separates a useful assistant from a mess.
What the model actually knows about a project
A model reads a prompt. It does not read the repository, the commit history, the incident from three months ago that forced a particular column to stay nullable, or the naming convention that a team adopted after a painful migration. Every one of those details is a constraint. Constraints are the raw material of project-specific code.
Ask for a user model and the response will contain fields like id, email, createdAt, and updatedAt. Sensible. But the real project has a user table where the primary key is a UUID generated by a specific Postgres extension, the email is stored lowercased by a trigger, and the timestamps are in UTC because a reporting job silently double-counted anything else two summers ago. The model's version is a sketch of a user. The project's version is a contract.
This is not a failing of the model so much as a boundary of what any single prompt can carry. A person could read the schema, the migrations, and the last dozen pull requests. The model gets whatever the prompt includes and fills the rest with the statistical average of code it has seen. The average is often clean. It is rarely correct for a specific place.
Boilerplate is where the model earns its keep
None of this makes the tool useless. It makes it useful in a narrower zone than the marketing suggests. Boilerplate is the sweet spot. A retry decorator with exponential backoff, a health check endpoint, a Dockerfile for a standard Python service, a GitHub Actions workflow that runs tests on push: these are patterns with a hundred correct implementations, and the model has seen all of them. The cost of a small imperfection is low because the code is easy to read, easy to test, and does not encode any business logic.
There is a real time saving here. A service that needs a logging setup, a settings module, and a basic CI pipeline can be scaffolded in twenty minutes instead of an afternoon. The output will look like every other service, which for boilerplate is a virtue. Uniformity in scaffolding is fine. Uniformity in the parts that make the product distinct is a problem.
The tell is how the code fails. Boilerplate fails loudly and locally: a missing env var, a port already in use, a failing test with a clear message. Project-specific code fails quietly, in production, weeks later, when the assumption baked into it finally meets the real world.
The generic function that looked fine in review
A concrete example helps. A team asks for a function that calculates a customer's order total. The model returns something like calculateTotal(items, taxRate, discount). It is clean, readable, and passes a quick glance. It also assumes a single tax rate, a percentage discount, and that items carry a price field.
The actual system has per-region tax tables, discount codes that apply before tax in some jurisdictions and after in others, and a price field that is stored in minor units to avoid floating point drift. The model's function is a reasonable toy. Wired into the checkout path, it produces numbers that are wrong in ways nobody notices until an accountant does.
The interesting part is how this got merged. The function looked correct. It had a docstring. It had tests that the model also generated, and those tests used the same assumptions as the function, so they passed. Reviewers saw green checkmarks and clean diffs. The mismatch lived in the space between the code and the domain, and that space is exactly where automated review has no opinion.
Why the generated tests can be a trap
Tests written by the same model that wrote the code inherit the same blind spots. If the model believes tax is a single percentage, its tests will assert that a single percentage works. The suite is internally consistent and externally wrong. This is a subtler failure than a broken test, because a broken test gets attention and a passing test gets trust.
The antidote is boring: tests should be written against the real requirements, ideally by someone who has read the spec, the ticket, or the compliance document. When a model generates both the implementation and the test, the pair should be treated as a first draft of both, never as a finished unit.
Reading the output for tells of genericness
Generated project code has a recognizable texture. It tends to be more defensive than the surrounding code, with null checks and try/catch blocks that the codebase does not use. It favors generic names: data, result, item, handler, process, manage. It writes docstrings for private helpers that the rest of the repo leaves undocumented. It imports a library the project does not depend on, like lodash in a codebase that has deliberately avoided utility libraries, or axios in a project standardized on fetch.
None of these is a bug on its own. Together they signal that the code was written for an imagined project rather than this one. A quick scan for naming style, error handling conventions, and imports catches most of it before review.
There is also a structural tell. Project-specific code tends to be shaped by its callers: a function that exists because one screen needs it, with an awkward parameter or two that reflect a real UI constraint. Model code tends to be shaped by its category: a general-purpose function that could serve any caller, with tidy parameters and optional arguments that nobody in this codebase will ever pass. The awkwardness is often the fingerprint of fit.
Giving the model enough context to be specific
The gap narrows when the prompt carries real constraints. Pasting the relevant schema, the existing module the new function will live beside, and two or three examples of similar code from the same repo changes the output substantially. The model starts matching conventions it can see rather than conventions it has averaged.
This is more work than a one-line prompt, and it is the difference between a plausible draft and a usable one. A prompt that says "write a function to validate an email" gets a regex from 2014. A prompt that includes the existing validation module, the error type the project uses, and the note that emails are already lowercased upstream gets something a reviewer can work with.
Even with good context, the output should be treated as a proposal. The model does not know which constraints matter most, which edge cases have already burned the team, or which shortcut is acceptable because the system downstream handles it. Those judgments stay with the person who has lived in the codebase.
Where the boundary should sit on a team
A workable rule: let the model write the scaffolding, and keep the domain logic under human authorship or close human review. Scaffolding is forgiving. Domain logic is where the money, the compliance, and the customer trust live. The asymmetry in cost of error is large enough to justify the asymmetry in process.
This is not a permanent arrangement. Models are getting better at absorbing context, and the boundary will move. But the boundary exists today, and teams that ignore it tend to discover it the same way: a clean pull request, a green test suite, and a bug report from a customer who notices the total is off by a few cents.
The practical habit is simple enough. Before accepting generated code, ask one question: could this have been written by anyone with general knowledge of programming, or does it show evidence that someone knew this project? If the answer is the first, it is boilerplate and fine. If the answer is the second but the code came from a model that has never seen the project, that is the moment to slow down.

