For AI agentsA Markdown index of these docs is at /llms.txt. Every page is also Markdown: add .md to its address.

Agent Rules / Structure and state

How should generated code be handled for coding agents?

Rule AR-23

Generated code is committed, or its generator is in the repo with the command to run it. Mark it, and tell agents to edit the source.

An agent that opens client.py, finds a bug, and fixes it in place has done the wrong thing if the file is regenerated from a schema tomorrow. It can't know that unless the file says so. Commit the output with a header that names the generator and the command, or keep the output out of the repo and put the generator and the command where the agent will read them. Then the agent edits the schema, runs the command, and reads the result.

Why it happens

Generated files look like source. They have functions, imports and callers, and nothing in the language tells a reader which files are written by hand. Three things decide whether an agent handles them well:

  • Marking. The Go project gives one documented convention: a line matching ^// Code generated .* DO NOT EDIT\.$ before the first non-comment, non-blank text in the file. Tools and people can find generated files by that line. Other languages have no single rule, so copy the shape: one comment at the top that says it's generated, by what, and how to regenerate.
  • Explicit runs. The Go docs add that go generate is never run by go build or go test, and must be run explicitly. The same applies to most generators: if the command isn't written down, the next person (or agent) learns it by trial.
  • Visibility to code hosts. GitHub reads a root-level .gitattributes with the same matching rules as .gitignore. Adding linguist-generated to a line (search/index.json linguist-generated) hides the file in diffs by default and leaves it out of the repository's language statistics. A minus sign (bootstrap.min.css -linguist-generated) unmarks a file that would be treated as generated. The linguist docs describe the effect as "excluded from stats, hidden in diffs", and say common generated files such as minified JavaScript are detected automatically. This attribute helps human reviewers. It doesn't stop an agent reading or editing the file.

Committed or built on demand. Both are workable, and they fail differently:

  • Committed output is searchable and type-checkable in a fresh checkout. An agent finds the callers of a generated function. The risk is stale output, so CI should regenerate and fail on a diff.
  • Built on demand keeps the repo small. In a fresh checkout the code doesn't exist, and every tool that reads files sees nothing until the generator has run. An agent has to run the command before anything resolves, so the command needs to be at the top of the instructions it reads.

Where tools see it. Excluding generated files from linting is normal: Ruff has exclude, extend-exclude and lint.exclude, and ESLint has globalIgnores(). Pyright's exclude marks paths as not part of the project, though the docs say files in excluded paths can still be analyzed if included source files import them, and its ignore setting suppresses diagnostics for the paths you list. So a generated module that your code imports stays visible to the type checker, and that's what you want.

Bad and good

Take an API client generated from a schema file.

python# bad: committed output, no header, no command, patched by hand # api/client.py class UsersApi: def get_user(self, user_id: int) -> dict: # someone fixed the return type here return self._get(f"/users/{user_id}")
typescript// bad: committed output, no header, no command, patched by hand // src/api/client.ts export class UsersApi { getUser(id: number): Promise<any> { // edited by hand last month return this.get(`/users/${id}`); } }

The next regeneration overwrites the hand patch. An agent that fixes a bug here fixes it once, and the fix disappears.

python# good: header, source and command are all written down # api/client.py # Code generated by scripts/gen_client.py from api/schema.json. DO NOT EDIT. # Regenerate: python scripts/gen_client.py class UsersApi: def get_user(self, user_id: int) -> User: ...
typescript// good: header, source and command are all written down // src/api/client.ts // Code generated by scripts/gen-client.mjs from api/schema.json. DO NOT EDIT. // Regenerate: npm run gen:client export class UsersApi { getUser(id: number): Promise<User> { /* ... */ } }

Alongside it, a .gitattributes line for reviewers and the AGENTS.md block below for agents:

gitattributesapi/client.py linguist-generated src/api/client.ts linguist-generated

Trade-offs and when to build on demand

  • Committed output costs diff noise. Big regenerations make big diffs. linguist-generated collapses them on GitHub, and a CI check that regenerates and compares keeps them honest.
  • Build-time generation keeps the repo clean. It suits very large outputs, such as bundled assets or large compiled schemas. It asks more of the instructions: the command has to be in AGENTS.md and the README.
  • A header is a convention, not a lock. Nothing stops a hand edit. A CI regeneration check is the real guard.
  • Generated barrels (see AR-02) are acceptable with star re-exports when the generator owns them and no one edits them by hand.
  • Mixing hand-written and generated code in one file is the worst case for agents. Keep the generated part in its own file, and subclass or wrap it from hand-written code.
  • Large generated files feed the size question in AR-24. Keep them out of the reading path when you can.

Enforce it

ToolSettingWhat it catchesChecked
git / GitHub.gitattributes with linguist-generatedmarks files as generated: hidden in diffs, left out of language stats2026-10-30
ruffextend-exclude or lint.excludekeeps generated files out of lint runs (defaults are empty)2026-10-30
eslintglobalIgnores([...]) in eslint.config.jskeeps generated files out of lint runs2026-10-30
pyrightexclude and ignoreexclude takes paths out of the project; ignore suppresses diagnostics for them2026-10-30
CIregenerate, then git diff --exit-codecommitted output that has drifted from its source or been edited by handgit-diff docs: --exit-code exits with 1 if there were differences and 0 if there were none

In pyproject.toml:

toml[tool.ruff] extend-exclude = ["api/client.py"]

In eslint.config.js:

jsimport { defineConfig, globalIgnores } from "eslint/config"; export default defineConfig([globalIgnores(["src/api/client.ts"])]);

Rule block for AGENTS.md / CLAUDE.md

markdown## Generated code - Files with a "Code generated ... DO NOT EDIT." header are outputs. Don't edit them. Change the source named in the header, then run the command named in the header. - Generated files: api/client.py, src/api/client.ts. Sources: api/schema.json. Command: python scripts/gen_client.py and npm run gen:client. - After running a generator, show the diff of the generated files in your final message. - If a bug is in generated output and the generator can't fix it, say so in the final message rather than patching by hand.

Edge cases

  • Lockfiles and snapshots are generated, and they get a different treatment. Review them as data, and let the package manager write them.
  • Protobuf, OpenAPI and GraphQL outputs commonly have a header already. Check that it names the command, and add the command in a wrapper script if it doesn't.
  • Generated tests (snapshot files) are generated by the test runner. Update them with its documented flag, and read the diff.
  • Minified and bundled files are detected by GitHub automatically, and they don't belong in agent read paths either.
  • The generator itself is code agents edit. Put a test next to it that runs it on a small schema and compares the output to a fixture.

What LLMGRAPH shows

LLMGRAPH lists callers of generated code like any other code and does not say the file is generated; the header and the AGENTS.md block carry that.

References

  • GitHub Docs, customizing how changed files appear on GitHub (linguist-generated): https://docs.github.com/en/repositories/working-with-files/managing-files/customizing-how-changed-files-appear-on-github
  • Linguist, overrides: https://raw.githubusercontent.com/github-linguist/linguist/main/docs/overrides.md
  • Go command documentation, generating Go files (header convention, explicit run): https://pkg.go.dev/cmd/go#hdr-Generate_Go_files_by_processing_source
  • Ruff settings (exclude, extend-exclude, lint.exclude): https://docs.astral.sh/ruff/settings/
  • ESLint, ignore files: https://eslint.org/docs/latest/use/configure/ignore
  • Pyright configuration (exclude, ignore): https://raw.githubusercontent.com/microsoft/pyright/main/docs/configuration.md

Changelog

  • 2026-10-30: draft 1.
  • 2026-10-30: docs checks resolved.
  • AR-02 Do barrel files hide calls from coding agents?
  • AR-21 Do metaclasses hide code from coding agents?
  • AR-26 How does an agent know an edit is finished?

Last verified

For agentsthis page as Markdown/agent-readable/ar-23.mdllms.txt