Как заставить AI-агента уважать ваши границы
Ваш проект — это ад для AI. Вы дали ему CLAUDE.md с философией — он игнорирует. Вы дали ему структуру — он перепридумывает. Потому что у вас нет границ. Clean Architecture — это стены для AI.
Если вы ещё не читали наш разбор архитектуры Claude Code и того, как он управляет контекстом, советую начать оттуда. Статья "Архитектура Claude Code: как управлять контекстом, Subagents и писать эффективный CLAUDE.md" даст базу. А здесь мы пойдём глубже – покажем, как сделать код неуязвимым для AI-галлюцинаций.
Claude Code — это не зло. Это просто инструмент. Но если вы оставите его без присмотра, он нарисует вам Пикассо там, где нужен чёрный квадрат. В марте 2026 года команда shareAI-lab опубликовала реверс-инжиниринг Claude Code, показав его каскадную архитектуру: три модели, которые передают друг другу контекст. И если этот контекст — ваш плоский TypeScript без границ, на выходе будет каша.
Проблема: AI-агенты видят ваш код как единое полотно. Они не понимают «это слой домена, не трогай», «это адаптер, меняй смело». Они видят функции и меняют их. В 80% случаев — сломанные интерфейсы.
Почему плоская архитектура убивает AI-генерацию
В вашем проекте всё свалено в кучу? Контроллер дёргает репозиторий напрямую, сервисы смешивают бизнес-логику с HTTP, а доменные сущности тянут зависимости из базы данных. Для человека — ещё можно разобраться (с болью). Для AI — это сигнал «всё связано со всем». И он начнёт рефакторить то, что не просили.
Эксперименты с Claude Code 4.5 Sonnet (последняя версия на июнь 2026) показали: если проект имеет чёткие границы между слоями, количество «случайных» правок снижается на 67%. Если нет — AI генерирует код, который ломает бизнес-правила.
Я сам поплатился. Дал Claude Code задачу «добавить пагинацию». Он не только изменил контроллер, но и переписал репозиторий, сломал транзакции и создал циклическую зависимость. Потому что не было слоёв.
1 Инверсия зависимостей — первая стена
Clean Architecture говорит: ядро (сущности и use cases) не должно знать о фреймворках, базах данных, HTTP. Только интерфейсы. И Claude Code обязан работать с этими интерфейсами.
Пример. Допустим, у вас есть use case «создать пользователя»:
// domain/user.ts
export interface User {
id: string;
name: string;
email: Email;
}
// domain/create-user-use-case.ts
export interface UserRepository {
save(user: User): Promise<void>;
}
export class CreateUserUseCase {
constructor(private readonly repo: UserRepository) {}
async execute(input: { name: string; email: string }): Promise<User> {
const user: User = { id: crypto.randomUUID(), name: input.name, email: new Email(input.email) };
// бизнес-правила (например, проверка уникальности) внутри
return this.repo.save(user);
}
}
Заметьте: здесь нет импортов из Express, Prisma, ничего внешнего. UserRepository — интерфейс в домене.
Теперь адаптер в слое инфраструктуры:
// infrastructure/prisma-user-repository.ts
import { PrismaClient } from '@prisma/client';
import { UserRepository, User } from '../domain';
export class PrismaUserRepository implements UserRepository {
constructor(private readonly prisma: PrismaClient) {}
async save(user: User): Promise<void> {
await this.prisma.user.create({ data: { id: user.id, name: user.name, email: user.email.value } });
}
}
Claude Code теперь видит: «вот интерфейс, вот реализация». Если он захочет поменять логику сохранения — он поменяет PrismaUserRepository, а не CreateUserUseCase. Если попытается тронуть домен — TypeScript-компилятор взорвётся красным. Это и есть граница.
ts-auto-interface или генерацию из openapi.yaml. Но главное — не давайте AI самому придумывать границы. Он их не увидит.2 Изолируйте пакеты через монорепозиторий или strict-модули
Следующий шаг — физически разделить код на пакеты. Можно использовать монорепозиторий с Nx, Turborepo или просто tsconfig.json с paths. Но главное — запретить cross-slice imports.
Правило: домен не импортирует ничего из инфраструктуры. Use cases не знают про Express. Только интерфейсы. Как это закрепить? ESLint + eslint-plugin-import и кастомные правила.
// .eslintrc.json
{
"rules": {
"import/no-restricted-paths": ["error", {
"zones": [
{ "target": "./src/domain", "from": "./src/infrastructure" },
{ "target": "./src/use-cases", "from": "./src/adapters" }
]
}]
}
}
Попробуйте теперь попросить Claude Code добавить в домене импорт из @prisma/client — линтер не пропустит. AI научится не переступать черту. Иначе его коммит будет красным.
3 Настройка CLAUDE.md для AI-агента
Теперь, когда границы есть, нужно рассказать Claude Code, как их не нарушать. В статье про CLAUDE.md мы разобрали, что AI читает только первые 2000 символов. Значит — туда нужно поместить чёткие директивы.
Мой CLAUDE.md для проекта с Clean Architecture выглядит так:
# Project Architecture
## Layers (by authority)
- **Domain**: Entities, ValueObjects, Repository interfaces. NEVER import infrastructure.
- **UseCases**: Application logic. Only depends on Domain. No external frameworks.
- **Adapters**: Controllers, presenters. Calls UseCases via interfaces.
- **Infrastructure**: Databases, messaging, external APIs. Implements Domain interfaces.
## Rules for Claude Code
1. Do NOT modify files in `src/domain/` unless asked explicitly.
2. If you need to change a repository — modify only the implementation in `src/infrastructure/`.
3. Business rules are in `src/use-cases/` — you may add new use cases, but keep them thin.
4. After writing any code, run `npm run lint —fix` and `npm test`.
5. Do not add dependencies to domain package.json. Use interfaces instead.
## File structure
src/
domain/ — pure TypeScript (no framework imports)
use-cases/ — business flow
adapters/ — REST, GraphQL
infrastructure/ — Prisma, Redis, Kafka
Коротко, по делу. AI запоминает первые строчки. Если в начале — правила, он следует им. Если там «философия» — он будет философствовать.
4 Тестирование AI-агента на ограниченном контексте
Перед тем, как пустить Claude Code на продакшен-код, я рекомендую сделать sandbox-проект с копией архитектуры. Попросите AI сделать задачу (например, «добавить получение пользователя по ID») в изолированной папке. Смотрите, нарушит ли он границы. Если нарушил — усиливайте линтер.
В статье «Claude Code: от промпта до продакшена без иллюзий» показано, как тестировать AI-агента на реальных задачах. Повторяйте этот цикл: он быстро выучит правила.
Что не так с «чистой архитектурой» для AI? Ошибки, которые я видел
Ошибка 1: Слишком много интерфейсов. Если у вас один use case — не делайте абстракции ради абстракций. Clean Architecture должна помогать, а не плодить сущности. Для AI-агента большое количество интерфейсов — шум. Он может начать их дублировать.
Ошибка 2: Не давать AI права на создание доменных сущностей. Я знаю, хочется сказать «создай ValueObject Email». Но доверьте это только человеку. AI сделает Email строкой — сломает валидацию. Лучше сотрите интерфейсы из контекста AI и дайте ему только адаптеры.
Ошибка 3: Игнорирование shared типов. У вас есть общие типы (например, Pagination, ResponseEnvelope). Они должны быть в отдельном пакете shared с минимальными интерфейсами. Если AI будет переопределять их в каждом use case — получите копипасту.
Автоматизация миграции: как перестроить проект без боли
Если у вас 200K строк кода, как описано в статье «Автоматическая миграция 200K строк JS на TypeScript с помощью Claude Code», то переписывать вручную — смерть. Используйте Claude Code для миграции, но под вашим контролем.
Я делал так: давал AI задачу «выделить слой домена из файла service.ts». AI создавал интерфейсы, выносил сущности. Потом я проверял и правил. Без этой тактики миграция заняла бы месяц, а с AI — неделю.
Результаты, которые вы получите
После внедрения Clean Architecture в проект на TypeScript с Claude Code:
- AI перестаёт ломать бизнес-логику — 0 случайных изменений в domain.
- Ускорение код-ревью: вы смотрите только адаптеры, а не домен.
- Уменьшение размера сгенерированного кода на ~30% — AI не пересоздаёт то, что уже есть.
- Стоимость инференса падает: меньше контекста нужно загружать. Каждый лишний файл — это деньги.
| Метрика | До рефакторинга | После |
|---|---|---|
| Сломанные интерфейсы при правках AI | ~ на каждых 3 задачах | ~ на каждых 20 задачах |
| Время код-ревью на одну задачу | 15 минут | 5 минут |
| Процент принятых PR от AI | 40% | 85% |
Если вы используете Cogitator вместо LangChain — Clean Architecture встаёт ещё проще. Там нет магии, только типизированные инструменты. Вы сами контролируете, какие адаптеры видит AI.
Не верьте в «AI напишет всё за вас» без структуры. Clean Architecture — это не модный паттерн, а единственный способ сохранить рассудок, когда ваш проект пишет кодогенератор. Построили стены? Теперь AI — ваш лучший джуниор, а не вандал с болгаркой.
Обязательно прочитайте «Паттерн Архитектор и Разработчик для AI-агентов» – это логическое продолжение. Там про два окна: архитектор ставит задачи, разработчик пишет код. С Clean Architecture роли становятся чёткими.