{"slug": "the-three-files-an-angular-monorepo-needs-before-an-agent-writes-a-line", "title": "The three files an Angular monorepo needs before an agent writes a line", "summary": "A developer published a guide for setting up Angular monorepos so coding agents follow architectural boundaries, centered on three files: a single AGENTS.md rules file that tool-specific files like CLAUDE.md and GEMINI.md point to, an ESLint dependency-constraint config using @nx/enforce-module-boundaries or Sheriff that turns those boundaries into a failing command, and the Angular team's published best-practices.md and angular/skills agent skills. The approach keeps AGENTS.md short and mostly negative, covering layout, non-negotiables such as standalone components and signals, and a definition of done that requires lint:arch and tests to pass.", "body_md": "*This is part 2 of 8 of the free series [AI with Angular: agents in your codebase](https://tt-tech.io/series/ai-with-angular), first published on [tt-tech.io](https://tt-tech.io/blog/three-files-before-an-agent-writes-a-line).*\n\n[The first part](https://tt-tech.io/blog/same-ai-two-outcomes) ended with a team whose agent lands inside the fence on its first try. This part builds the fence. It is three files: one the agent must read, one it must pass, one it must stay inside. An afternoon of work, and the rules that lived in people's heads become something the agent has to obey.\n\nEvery agent reads a project-level instructions file before it acts, and each tool has its own: `CLAUDE.md`, `GEMINI.md`, `.github/copilot-instructions.md`, `.cursor/rules/`. Several of them now also read `AGENTS.md`. Many teams leave these files empty, paste in the README, or write four copies that drift apart.\n\n**The agent sees your code, not your reasons. The rules file is where the reasons live.**\n\nWrite one file, `AGENTS.md`, and make every tool file a single line that points to it. In the demo repo `CLAUDE.md` is `@AGENTS.md` plus the block the Nx tooling adds, and `GEMINI.md` tells the agent to read and follow `AGENTS.md` before anything else. One source of truth, any agent. A tool's extras, like permissions or hooks, go in that tool's own settings; the rules never move.\n\nYou do not have to write the Angular part yourself. The Angular team publishes it: a `best-practices.md` on [angular.dev/ai](https://angular.dev/ai/develop-with-ai), and agent skills in [`angular/skills`](https://github.com/angular/skills). In the demo repo they sit in `.agents/skills/`, a folder several agents read, and the Angular and Atlas skills are linked into `.claude/skills/` for Claude Code. Your `AGENTS.md` keeps only what the Angular team cannot know: your boundaries, your legacy, your definition of done.\n\nWhat goes in it is short, concrete and mostly *negative*. The agent does not need your architecture vision. It needs the fence. Condensed from the demo repo's `AGENTS.md`:\n\n```\n# Atlas Bank: rules for coding agents (excerpt)\n\n## Layout\n- libs/domain         pure TypeScript, no Angular imports\n- libs/data-access/*  stores and services; may import domain\n- libs/ui             presentational only; never imports data-access\n- libs/feature/*      routed features; may import ui, data-access, domain\n\n## Non-negotiables\n- New components are standalone and use signals. No new NgModules.\n- Never edit libs/legacy/** unless the task file says migrate. Wrap it.\n- Crossing a library boundary needs an ADR link in the PR.\n\n## Before you say you are done\n- npm run lint:arch   passes\n- npm run test        passes without changed assertions\n- The diff is ≤ 300 lines unless the task file raises the limit\n```\n\nOne word there deserves a line. An ADR is an architecture decision record, a short dated note saying why a boundary exists. Asking the agent to link one is asking it to justify the crossing, and it usually cannot, which is the point.\n\nInstructions are suggestions. A failing command is not. The same boundaries become a lint rule, with `@nx/enforce-module-boundaries` in an Nx workspace or Sheriff in a plain Angular CLI project. From the demo repo's flat config:\n\n``` js\n// eslint.config.mjs (excerpt)\nconst depConstraints = [\n  { sourceTag: 'type:domain', onlyDependOnLibsWithTags: ['type:domain'] },\n  { sourceTag: 'type:data-access', onlyDependOnLibsWithTags: ['type:data-access', 'type:domain'] },\n  { sourceTag: 'type:ui', onlyDependOnLibsWithTags: ['type:ui', 'type:domain'] },\n  { sourceTag: 'type:feature', onlyDependOnLibsWithTags: ['type:feature', 'type:ui', 'type:data-access', 'type:domain'] },\n];\n// ...\n'@nx/enforce-module-boundaries': ['error', { depConstraints }],\n```\n\nNow the rules file can say \"run `lint:arch` before you finish\", and an agent that runs it will usually retry until it passes. \"Please respect the architecture\" has become a command that fails.\n\n*A `data-access` import in a `ui` component, and the build says no before a reviewer has to.*\n\nThe third file is per task, not per repo: the ask, written down before the agent reads it, with a scope, an out-of-scope and a \"done when\". It can be a Jira ticket, a GitHub issue with fixed headings, or a Markdown file in `docs/tasks/`. The form does not matter. What matters is one sentence:\n\n```\nScope: libs/feature/accounts only. Done when lint:arch and tests pass and the diff is under 300 lines.\n```\n\nThe size limit is the part that changes the most. Agents are excellent at satisfying explicit constraints and terrible at guessing implicit ones. With 300 in the task, a diff of well over a thousand lines fails the done-when before anyone reads it.\n\n**Prompt · let the agent find the holes in your rules file**\n\n```\nRead `AGENTS.md`. Then open `libs/` and list, as a numbered list, every rule you would need to do a feature in `libs/feature/accounts` that the file does not state: which imports are allowed, which store to use, how tests are written, what \"done\" means. Do not write code. Do not propose rules; only list what is missing.\n```\n\nRun it once per quarter. The list is your rules file's backlog.\n\n`AGENTS.md`, about a page, mostly \"never\". Point every tool file at it.` lint:arch` to \"done\".\nExercise: [module 1 in the demo repo](https://github.com/tt-tech/workshop-ai-with-angular/blob/main/exercises/m1-ai-assisted-workflow.md). Start without the files: `git switch track1/m1-start`. Then the same task with them: `git switch -c m1/you main`. Reference: `origin/track1/m1-solution`. Bring your own agent.\n\nWho writes that third file, and how fast, is [the next part](https://tt-tech.io/blog/from-ticket-to-task-file): the agent drafts it from the ticket, and a person decides.\n\n*Track 1, part 2 of the free series behind the [Fast and safe: AI in your Angular codebase](https://tt-tech.io/workshops/ai-with-angular) workshop.*", "url": "https://wpnews.pro/news/the-three-files-an-angular-monorepo-needs-before-an-agent-writes-a-line", "canonical_source": "https://dev.to/adilbenmoussa/the-three-files-an-angular-monorepo-needs-before-an-agent-writes-a-line-19c1", "published_at": "2026-11-12 21:14:52+00:00", "updated_at": "2026-11-12 21:23:01.741528+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-tools"], "entities": ["Angular", "Nx", "Claude Code", "GitHub Copilot", "Cursor", "Gemini", "Sheriff", "Atlas Bank"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/the-three-files-an-angular-monorepo-needs-before-an-agent-writes-a-line", "markdown": "https://wpnews.pro/news/the-three-files-an-angular-monorepo-needs-before-an-agent-writes-a-line.md", "text": "https://wpnews.pro/news/the-three-files-an-angular-monorepo-needs-before-an-agent-writes-a-line.txt", "jsonld": "https://wpnews.pro/news/the-three-files-an-angular-monorepo-needs-before-an-agent-writes-a-line.jsonld"}}