Подробный разбор архитектуры Claude Code «под капотом» — как устроен агентный цикл, инструменты, права доступа, суб-агенты, память, MCP и продакшн-обвязка. Гайд построен по принципу «от простого к сложному»: сначала цикл в 15 строк, потом полноценный продакшн-агент. Материал собран из публично доступных источников и обсуждений сообщества и предназначен только для изучения и технического исследования.
Note
Этот репозиторий — учебный. Он объясняет паттерны современных кодинг-агентов на примере Claude Code. Внутренние детали реализации (кодовые имена, флаги, точная структура файлов) могут отличаться от версии к версии — важны не они, а принципы, которые переносятся на любой агент.
Tip
Популярные ресурсы по Машинному Обучению, ИИ и анализу данных.
🧠 Machine Learning — авторский Telegram-канал, который содержит всю базу для работы с ИИ-моделями. Дайджесты лучших проектов, разбор кода, инструкции по запуску LLM, подготовка к собесу и многое другое.
📚 Data Science — редкая литература, статьи, курсы и уникальные гайды для ML-специалистов любого уровня. Читайте, развивайтесь, практикуйте.
💼 Machine Interview — база с 1900 вопросами с собеседований по машинному обучению. Вы легко получите оффер, изучив популярные вопросы.
Telegram лучше — подписывайтесь.
Гайд рассчитан на три типа читателей — выберите свой маршрут, чтобы не читать лишнее.
| Вы… | Начните с | Дальше | Можно пропустить |
|---|---|---|---|
| 🟢 Новичок — хотите просто начать | разделы 1–4 | 5, 16, 26 | 18–25 (пока) |
| 🟡 Практик — уже пользуетесь | 10–12, 27–29 | 16, 19–22 | 6–7 (обзорные) |
| 🔴 Архитектор — строите своего агента | 5–9 | 13, 18, 23–25 | ничего 🙂 |
Tip
Хотите одним махом понять «зачем вся эта сложность»? Прочитайте раздел 5A «Что такое харнесс» — он связывает голый цикл (раздел 5) со всей продакшн-обвязкой (раздел 18) в одну картинку.
Читать можно и по порядку — материал идёт «от простого к сложному»: сначала цикл в 15 строк (раздел 5), потом полноценная продакшн-обвязка (раздел 18). Если торопитесь — раздел 34 «Шпаргалка» держите открытым рядом как справочник.
Часть I. Основы
- Кому и зачем это нужно
- Что такое агент простыми словами
- С чего начать: установка за 5 минут
- Первая сессия: 10 команд, которые стоит знать
Часть II. Как это устроено внутри 5. Базовый агентный цикл (сердце всего)
- Обзор архитектуры
- Жизненный цикл одного запроса
- Система инструментов (Tools)
- Система прав доступа (Permissions)
- Слэш-команды
- Хуки и settings.json
- MCP: подключаем внешние инструменты
Часть III. Продвинутое 13. Суб-агенты и мультиагентность 14. Управление контекстом (Compact) 15. Память и знания по требованию 16. Режим планирования (Plan Mode) 17. Сохранение и восстановление сессий 18. 12 механизмов продакшн-обвязки 19. Наблюдаемость и трейсинг агента 20. Стоимость и оптимизация токенов 21. Кэширование промптов (Prompt Caching) 22. Тестирование и оценка агентов (Evals) 23. Безопасность и защита от prompt injection 24. Отказоустойчивость: ретраи, таймауты, идемпотентность 25. Стриминг и параллелизм под нагрузкой
Часть IV. Практика 26. Практикум: собираем мини-агент сами 27. Рецепты: реальные сценарии использования 28. Практические примеры: разбор по шагам 29. Лучшие практики и антипаттерны 30. Решение проблем (Troubleshooting) 31. Глоссарий 32. Частые вопросы (FAQ) 33. Куда двигаться дальше 34. Шпаргалка (Quick Reference)
Этот гайд для тех, кто хочет понять не как пользоваться Claude Code, а как он устроен изнутри. Если вы разработчик и хотите построить собственного кодинг-агента, разобраться в паттернах продакшн-агентов или просто понять, что происходит между вашим запросом и ответом модели — вы по адресу.
Гайд полезен трём типам читателей. Новичку он даст пошаговый вход: установка, первые команды, ментальная модель. Практику — рецепты, лучшие практики и разбор частых ошибок. Инженеру-архитектору — детальный разбор того, как плоский цикл превращается в продакшн-систему с правами, суб-агентами и изоляцией.
Мы идём от самого простого (цикл в 15 строк) к сложному (мультиагентные команды, изоляция в git worktree), объясняя каждый слой отдельно. Читать можно последовательно или прыгать по оглавлению.
Обычный чат с моделью — это «вопрос → ответ». Модель не может ничего сделать: она только генерирует текст. Агент отличается одним: у него есть инструменты (tools) и цикл.
Представьте помощника, которому вы дали не только возможность говорить, но и руки: он может читать файлы, запускать команды, искать в интернете. После каждого действия он смотрит на результат и решает, что делать дальше — пока задача не выполнена. Вот и всё. Агент = модель + инструменты + цикл, который крутится, пока есть работа.
ЧАТ: АГЕНТ:
вопрос -> ответ вопрос -> [подумать -> действие -> результат]* -> ответ
(один шаг) (много шагов, пока задача не решена)
Всё остальное в этом гайде — про то, как сделать этот простой цикл надёжным, безопасным и масштабируемым.
Три инструмента решают разные задачи. Путаница между ними — частая причина разочарования («агент слишком медленный», «автодополнение слишком глупое»).
| Автодополнение (Copilot) | Чат с моделью | Агент (Claude Code) | |
|---|---|---|---|
| Что делает | достраивает строку/блок | отвечает текстом | действует в цикле до результата |
| Видит проект | текущий файл + немного | что вы вставили | читает файлы сам |
| Запускает код | нет | нет | да (тесты, сборка, git) |
| Итерирует | нет | вы вручную | сам: правка → тест → правка |
| Лучшее применение | быстрый набор кода | вопрос-объяснение | многошаговые задачи |
| Стоимость/скорость | мгновенно, дёшево | быстро | медленнее, дороже |
Практическое правило: автодополнение — когда вы сами пишете код и знаете, что; чат — когда нужно понять или спросить; агент — когда задача требует нескольких шагов с обратной связью («почини тест», «отрефактори модуль», «разберись в баге»). Не гоняйте агента ради однострочника — это как вызывать эвакуатор, чтобы переставить машину на метр.
Шаг 1. Проверьте окружение. Нужен Node.js версии 18 или выше:
node --version # ожидается v18.x или вышеЕсли Node не установлен — скачайте с nodejs.org или поставьте через менеджер версий (nvm, fnm).
Шаг 2. Установите Claude Code глобально:
npm install -g @anthropic-ai/claude-codeШаг 3. Перейдите в папку проекта и запустите:
cd your-project
claudeШаг 4. Авторизуйтесь. При первом запуске откроется браузер для входа в аккаунт Anthropic. Токен сохранится локально, повторно логиниться не нужно.
Шаг 5. Задайте первый вопрос, например: «объясни структуру этого проекта». Готово — вы внутри агентного цикла.
Tip
Запустите claude именно в корне проекта — так агент сразу видит контекст (файлы, git, CLAUDE.md). Из пустой папки пользы будет меньше.
| Команда | Что делает |
|---|---|
claude --version |
показывает версию |
claude "привет" |
одноразовый запрос без входа в REPL |
claude |
интерактивный режим (REPL) |
claude --help |
список всех флагов |
Внутри интерактивного режима (REPL) полезны слэш-команды. Вот минимальный набор новичка:
| Команда | Зачем |
|---|---|
/help |
список всех доступных команд |
/clear |
очистить контекст и начать заново |
/init |
сгенерировать CLAUDE.md для текущего проекта |
/model |
посмотреть/сменить модель |
/memory |
открыть/отредактировать файлы памяти |
/compact |
вручную сжать контекст, сохранив суть |
/review |
запросить ревью изменений |
/resume |
вернуться к прошлой сессии |
/cost |
показать потраченные токены и стоимость |
/exit |
выйти из сессии |
Tip
Начните любой новый проект с /init — Claude просканирует репозиторий и создаст CLAUDE.md с описанием стека, команд сборки и структуры. Это резко повышает качество последующих ответов.
В основе Claude Code лежит очень простая идея. Всё остальное — надстройка над ней.
ГЛАВНЫЙ ЦИКЛ
============
Пользователь --> messages[] --> Claude API --> ответ
|
stop_reason == "tool_use"?
/ \
да нет
| |
выполнить инструмент вернуть текст
добавить tool_result
вернуться в цикл ------> messages[]
Разберём по шагам, что происходит:
- Пользователь отправляет запрос — он попадает в массив
messages[](вся история диалога). - Массив уходит в Claude API вместе со списком доступных инструментов.
- Модель отвечает. Ключевое поле ответа —
stop_reason. - Если
stop_reason == "tool_use"— модель захотела вызвать инструмент. Мы его выполняем, кладём результат обратно вmessages[]какtool_resultи возвращаемся к шагу 2. - Если нет — это финальный текстовый ответ, цикл завершён.
Вот и весь «магический» агент. Claude Code оборачивает этот цикл в продакшн-обвязку: права доступа, стриминг, параллелизм, сжатие контекста, суб-агенты, персистентность и MCP. Дальше по гайду мы разберём каждый слой этой обвязки.
Important
Запомните главную мысль: цикл не меняется, сколько бы возможностей мы ни добавляли. Инструментов может быть 3 или 300 — структура остаётся той же. Именно это делает архитектуру расширяемой.
Мы уже видели «сердце» агента — цикл в 15 строк (раздел 5). Но голый цикл в проде долго не живёт: он не знает про права, падает от первой же ошибки API, теряет сессию при сбое и радостно выполняет rm -rf, если так «попросил» прочитанный файл. Харнесс (agent harness, «обвязка») — это всё, что оборачивает цикл, чтобы он стал безопасным, наблюдаемым и восстановимым.
Простыми словами: если модель — это двигатель, а цикл — коленвал, то харнесс — это кузов, ремни безопасности, приборная панель и тормоза. Двигатель крутится одинаково; отличие продакшн-агента от учебного скрипта — целиком в обвязке.
ХАРНЕСС (обвязка)
┌──────────────────────────────────────────────────────┐
│ сборка промпта · права · ретраи · таймауты · логи │
│ сжатие контекста · персистентность · стриминг │
│ ┌──────────────────────────────────┐ │
│ │ ЦИКЛ (раздел 5) │ │
│ │ API → stop_reason? → инструмент │ │
│ └──────────────────────────────────┘ │
│ ↑ вход (промпт, /команды) выход (текст, стоимость)│
└──────────────────────────────────────────────────────┘
| Проблема голого цикла | Что добавляет харнесс |
|---|---|
| Выполняет любую команду вслепую | ворота прав + deny-правила (раздел 9) |
| Падает при 429/500/таймауте | ретраи с backoff, таймауты (раздел 24) |
| Забывает начало при переполнении | сжатие контекста (раздел 14) |
| Теряет всё при сбое процесса | запись сессии на диск (раздел 17) |
| Непонятно, что и почему сделал | трейсинг и логи (раздел 19) |
Читайте сверху вниз — так обвязка «наматывается» на цикл слой за слоем.
- Сборка входа. Разобрать
/команды, склеить системный промпт (инструменты + CLAUDE.md), нормализовать историю. Именно здесь цикл получает контекст, а не только голый вопрос. - Ворота прав. Перед каждым вызовом инструмента — хуки, правила
allow/deny, при необходимости вопрос пользователю. Опасное блокируется до выполнения. - Исполнение и устойчивость. Вызов инструмента с таймаутом; транзиентные ошибки (429/500) — ретраятся, результат (в т.ч. ошибка) возвращается в цикл как
tool_result. - Управление контекстом. Следим за бюджетом токенов; при переполнении — сжатие старой истории, чтобы цикл не «ослеп».
- Персистентность. Каждый ход пишется в JSONL синхронно — сессию можно продолжить (
--continue) даже после падения. - Наблюдаемость и вывод. Стриминг ответа в терминал, лог каждого витка (модель, токены, решение прав, длительность), финальная стоимость.
ПРОМПТ
│
▼
[1 вход] собрать промпт + /команды + CLAUDE.md
│
▼
[6 лог] ──► записать транскрипт (JSONL) ◄── [5 персистентность]
│
▼
┌─────────────── ЦИКЛ ───────────────┐
│ [3] API (ретрай/таймаут/стриминг) │
│ │ │
│ stop_reason == tool_use? │
│ │ да │
│ [2] ворота прав → allow/deny │
│ │ │
│ [3] выполнить → tool_result │
│ │ │
│ [4] контекст переполнен? → сжать │
│ └──────── назад в API ──────────┘
└───────────────────────────────────────┘
│ stop_reason != tool_use
▼
ФИНАЛ: текст + стоимость + id сессии
Тот же цикл из раздела 26, но обёрнутый четырьмя базовыми слоями обвязки. Разница в комментариях # [харнесс].
import time, json
def run(prompt, log):
messages = [{"role": "user", "content": prompt}]
log_event(log, "session_start", {"prompt": prompt}) # [харнесс: лог]
while True:
resp = call_api_with_retry(messages, TOOLS) # [харнесс: ретрай/таймаут]
log_event(log, "api_turn", { # [харнесс: трейс витка]
"stop": resp.stop_reason, "in": resp.tokens_in, "out": resp.tokens_out,
})
messages.append(resp.message)
if resp.stop_reason != "tool_use":
log_event(log, "final", {"cost": resp.cost})
return resp.text
for call in resp.tool_calls:
if not check_permission(call): # [харнесс: ворота прав]
result = {"error": "denied", "is_error": True}
else:
result = run_tool_safely(call) # [харнесс: таймаут + is_error]
messages.append({"role": "tool", "content": result})
messages = compact_if_needed(messages) # [харнесс: сжатие контекста]
def call_api_with_retry(messages, tools, attempts=4):
for i in range(attempts):
try:
return claude_api(messages, tools=tools, timeout=60)
except TransientError: # 429/500/503/таймаут
time.sleep((2 ** i) + jitter()) # backoff + jitter
raise RuntimeError("API недоступен после ретраев")Important
Ключевая мысль раздела: цикл не меняется — растёт харнесс. Всё, что превращает игрушку в продакшн-агент (безопасность, надёжность, наблюдаемость, восстановление), живёт в обвязке вокруг петли, а не внутри неё. Поэтому дальше по гайду мы разбираем именно слои харнесса по одному.
Возьмём запрос «Прогони тесты и почини упавший». Ниже — тот же цикл из раздела 5, но видно, как на каждом витке срабатывают слои обвязки: права, таймаут, ретрай, ошибка инструмента, сжатие. Сравните с «голой» трассировкой из раздела 26 — шаги те же, но каждый обёрнут защитой.
СЕССИЯ start → лог: session_id=a1b2, запись транскрипта на диск (JSONL)
ВИТОК 1
→ API (кэш-хит системного промпта) [21 наблюдаемость: in=8.2k tok]
← tool_use: bash("npm test")
[9 права] правило alwaysAllow "Bash(npm test:*)" → ALLOW без вопроса
[24 таймаут] запуск с лимитом 120с
→ tool_result: "1 failed: test_discount ... exit 1" (хвост вывода, [20] обрезка)
ВИТОК 2
→ API → ошибка 429 (rate limit) [24 ретрай]
⏳ backoff ~1с + jitter → повтор
← tool_use: read_file("src/cart.py")
[9 права] read-only → ALLOW; [25] можно параллельно с grep
→ tool_result: содержимое файла
ВИТОК 3
← tool_use: bash("rm -rf node_modules && ...")
[9 права] deny-правило "Bash(rm -rf *)" → DENY (блок до выполнения)
→ tool_result: {"error":"denied", is_error:true} ← цикл НЕ падает
ВИТОК 4 (агент выбрал другой путь после отказа)
← tool_use: edit_file("src/cart.py", ...)
[11 хук PostToolUse] prettier --write автоформат после правки
→ tool_result: "ok"
ВИТОК 5
[14 контекст] история > порога → авто-сжатие старых витков в резюме
→ API (свежие сообщения + резюме)
← tool_use: bash("npm test") → tool_result: "14 passed"
ВИТОК 6
← stop_reason=end_turn
← текст: "Причина — сброс флага в add_item(). Исправил, все тесты зелёные."
[19 финал] лог: 6 витков, 2 отказа прав обработаны, cost=$0.03, session=a1b2
Что здесь сделал именно харнесс, а не модель: пропустил безопасное без вопроса и заблокировал rm -rf (раздел 9), пережил 429 ретраем (24), не рухнул от отказа прав, а вернул ошибку в цикл (24), сжал контекст на лету (14), прогнал форматтер хуком (11) и залогировал весь прогон для разбора (19). Модель лишь принимала решения «что дальше» — надёжность обеспечила обвязка.
Tip
Такую трассировку полезно уметь читать по своим логам (раздел 19): по ней видно не только что сделал агент, но и какой слой харнесса вмешался на каждом шаге. Это первое, что помогает при разборе инцидента «агент повёл себя странно».
Харнесс — не отдельная фича, а зонтичное понятие для доброй половины разделов. Права — раздел 9, сжатие — 14, персистентность — 17, полный список из 12 механизмов — раздел 18, наблюдаемость — 19, отказоустойчивость — 24, стриминг и параллелизм — 25. Если раздел 18 отвечает на вопрос «что входит в обвязку», то этот раздел отвечает «зачем она вообще нужна и как слои складываются вместе».
Одна и та же петля, но разница в живучести — вот что добавляет обвязка.
| Аспект | Учебный агент (голый цикл) | Продакшн (с харнессом) |
|---|---|---|
| Опасная команда | выполнит вслепую | `deny`-правило блокирует до запуска |
| Ошибка API 429/500 | падает сразу | ретрай с backoff, потом продолжает |
| Зависший `bash` | висит вечно | таймаут → `tool_result` с ошибкой |
| Переполнение контекста | «забывает» начало | авто-сжатие старой истории |
| Сбой процесса | теряет всю работу | `--continue` поднимает сессию с диска |
| Разбор инцидента | «чёрный ящик» | лог витка: инструмент, аргументы, правило |
Наращивайте слои в порядке боли — от «опасно» к «удобно». Каждый пункт самодостаточен и уже даёт результат.
- Ворота прав. Блок-лист опасных команд (`rm -rf`, `git push --force`) + запрос подтверждения на остальное. Без этого агенту нельзя давать терминал.
- Ретраи + таймаут. Обернуть вызов API в backoff на 429/500 и поставить таймаут на каждый инструмент. Убирает 90% случайных падений.
- `is_error` в tool_result. Возвращать ошибку инструмента обратно в цикл, а не ронять процесс — агент сам попробует другой путь.
- Обрезка вывода. Отдавать в контекст только хвост/греп длинного вывода, иначе история раздувается и растёт стоимость.
- Запись сессии (JSONL). Писать каждый ход на диск синхронно — появляется `--continue` и разбор инцидентов.
- Лог витка. Хотя бы одна строка на виток: модель, токены, решение прав, длительность. Дальше это вырастает в полноценный трейсинг (раздел 19).
Important
Порядок важен: сначала безопасность (права), потом надёжность (ретраи/таймауты), потом восстановимость (персистентность). Красиво логировать агента, который выполняет `rm -rf`, — не приоритет.
Обвязку легко сделать так, что она создаёт ложное чувство безопасности или мешает работе. Ниже — частые ошибки и как их исправить.
| Антипаттерн | Чем плохо | Как правильно |
|---|---|---|
| `bypassPermissions` «чтобы не спрашивал» | одна инъекция в файле → `rm -rf` без вопроса | `default` + точечные `allow`-правила на рутину |
| Ретраить всё подряд | на `400/401/403` ретрай бессмысленен и маскирует баг | ретраить только транзиентное (`429/500/503`/таймаут) |
| Весь вывод инструмента в контекст | история и стоимость растут, кэш инвалидируется | обрезать до хвоста/грепа, отдавать только нужное |
| Падать при ошибке инструмента | цикл рушится, работа теряется | вернуть `is_error` в `tool_result`, дать агенту попробовать иначе |
| Логировать всё, включая секреты | ключи утекают в логи и трейсы | маскировать секреты до записи, не класть их в `messages[]` |
| Динамика в начале промпта (дата, id) | кэш префикса не срабатывает никогда | стабильное — в начало, изменчивое — в конец |
| Бесконечный цикл без предела | застрявший агент жжёт токены | лимит витков/бюджет + аккуратная остановка |
| «Проверил пару задач — работает» | одна правка ломает пять других сценариев | прогонять eval-набор при смене промпта/модели |
Warning
Самый опасный антипаттерн — сочетание «доступ к секретам + отправка данных наружу без подтверждения». Инъекция в прочитанном файле → чтение `.env` → `curl` на чужой сервер. Даже удобный харнесс не спасёт, если эти два права включены одновременно (см. раздел 23).
Харнесс — это фреймворк или библиотека? Нет, это архитектурный слой. Библиотека может помочь (SDK, очереди, логгер), но харнесс — это то, как вы обернули цикл: права, ретраи, персистентность. Его можно написать и на 100 строках без зависимостей.
Можно ли начать без харнесса и добавить потом? Да, именно так и стоит: сначала голый цикл (раздел 5), потом слои по одному в порядке боли (см. чек-лист выше). Не пытайтесь построить всё сразу.
Харнесс замедляет агента? Почти нет. Права и логи — микросекунды на фоне вызова модели. Наоборот, стриминг и параллельное чтение (раздел 25) делают агента отзывчивее, а кэш промптов (21) — дешевле.
Где заканчивается цикл и начинается харнесс? Цикл — это `while`: вызов API → проверка `stop_reason` → выполнение инструмента. Всё остальное (что до, вокруг и после этих трёх шагов) — харнесс.
Нужен ли харнесс для одноразового скрипта? Минимальный — да: хотя бы таймаут и блок опасных команд. Персистентность и трейсинг для разовой задачи избыточны — добавляйте их, когда агент идёт в прод или CI.
Чем харнесс отличается от промпта? Промпт говорит модели, что делать; харнесс контролирует, что реально произойдёт с её решениями. Хороший промпт без обвязки всё равно опасно пускать к терминалу.
Tip
Собираете своего агента? Наращивайте харнесс в порядке боли: сначала ворота прав (иначе опасно), потом ретраи и таймауты (иначе падает), затем персистентность (иначе теряете работу) и лишь потом сжатие и трейсинг. Не пытайтесь построить все слои сразу — добавляйте по одному и проверяйте.
СЛОЙ ВХОДА
cli --> main --> REPL (интерактивный режим)
--> QueryEngine (headless / SDK)
|
v
ДВИЖОК ЗАПРОСОВ (QueryEngine)
submitMessage(prompt) --> поток сообщений
├── собрать системный промпт (инструменты + CLAUDE.md)
├── обработать /команды
├── главный агентный цикл
│ ├── параллельное выполнение инструментов
│ ├── авто-сжатие контекста
│ └── оркестрация инструментов
└── стримить результат потребителю
|
├──────────────┬──────────────┐
v v v
ИНСТРУМЕНТЫ СЕРВИСЫ СОСТОЯНИЕ
40+ tools API-клиент права, история,
Bash/Read/Edit compact/mcp агенты, режимы
Glob/Grep телеметрия
WebFetch/Agent плагины
Архитектуру удобно читать сверху вниз как «слоёный пирог»:
- Слой входа решает, в каком режиме мы работаем: интерактивный REPL (человек за терминалом) или headless/SDK (агент внутри скрипта или CI).
- Движок запросов (QueryEngine) — дирижёр. Он собирает системный промпт, обрабатывает команды, крутит главный цикл и стримит ответ.
- Три опорных слоя: инструменты (что агент умеет делать), сервисы (API, сжатие, MCP, телеметрия) и состояние (права, история файлов, активные агенты, режимы).
Что именно происходит между нажатием Enter и появлением ответа:
ВВОД ПОЛЬЗОВАТЕЛЯ (промпт / слэш-команда)
|
v
разбор /команд, сборка UserMessage
|
v
сборка системного промпта (инструменты -> секции, память CLAUDE.md)
|
v
запись транскрипта на диск (JSONL)
|
v
┌── нормализация сообщений для API (сжатие при необходимости)
│ |
│ v
│ Claude API (стриминг) — POST с инструментами и системным промптом
│ |
│ ├── текстовый блок --> отдать потребителю
│ └── блок tool_use?
│ |
│ v
│ проверка прав (хуки + правила + запрос у пользователя)
│ ├── DENY --> tool_result(ошибка), продолжить цикл
│ └── ALLOW --> выполнить инструмент --> добавить tool_result
└────────── вернуться к вызову API
|
v (stop_reason != "tool_use")
финальное сообщение — текст, стоимость, id сессии
Обратите внимание на две важные детали. Во-первых, транскрипт пишется на диск до вызова API — если процесс упадёт, сессию можно восстановить. Во-вторых, отказ в правах не ломает цикл: агент получает tool_result с ошибкой и продолжает работу, может попробовать другой подход.
Каждый инструмент реализует единый интерфейс. Добавить инструмент = добавить один обработчик, при этом сам цикл не меняется.
ЖИЗНЕННЫЙ ЦИКЛ ИНСТРУМЕНТА
validateInput() — отсеять плохие аргументы заранее
checkPermissions() — проверка прав, специфичная для инструмента
call() — выполнить и вернуть результат
ВОЗМОЖНОСТИ
isEnabled() — проверка feature-флага
isConcurrencySafe() — можно ли запускать параллельно?
isReadOnly() — есть ли побочные эффекты?
isDestructive() — необратимые операции?
ОТРИСОВКА (React/Ink) — как показать ввод/вывод/прогресс в терминале
AI-СТОРОНА — prompt() и description() описывают инструмент для модели
Отдельно стоит подчеркнуть флаг isConcurrencySafe(). Инструменты только для чтения (например, поиск и чтение файлов) можно запускать параллельно — это резко ускоряет работу. А вот те, что меняют файлы или запускают команды, выполняются последовательно, чтобы не мешать друг другу.
| Категория | Инструменты | Назначение |
|---|---|---|
| Файлы | FileRead, FileEdit, FileWrite, NotebookEdit | чтение и правка файлов |
| Поиск | Glob, Grep, ToolSearch | навигация по кодовой базе |
| Выполнение | Bash, PowerShell | запуск команд в терминале |
| Веб | WebFetch, WebSearch | получение данных из интернета |
| Агенты/задачи | Agent, TaskCreate/Update/List, SendMessage | делегирование и координация |
| Планирование | EnterPlanMode, ExitPlanMode, TodoWrite | структурирование работы |
| MCP | MCPTool, ListMcpResources, ReadMcpResource | внешние интеграции |
| Система | Config, Skill, ScheduleCron | настройки и расширения |
Tip
Инструменты только для чтения (Glob, Grep, Read) безопасны и обычно выполняются без подтверждения. Осторожность нужна с Bash, Write и Edit — именно их стоит держать под контролем прав доступа (см. следующий раздел).
Права — главный механизм безопасности агента. Прежде чем инструмент выполнится, запрос проходит через несколько «ворот»:
ЗАПРОС НА ВЫЗОВ ИНСТРУМЕНТА
|
v
validateInput() — отклонить некорректный ввод до любых проверок
|
v
PreToolUse-хуки — пользовательские команды из settings.json
могут: одобрить / отклонить / изменить ввод
|
v
Правила прав — alwaysAllow / alwaysDeny / alwaysAsk
|
нет совпадения?
|
v
Интерактивный запрос — Allow Once / Allow Always / Deny
|
v
checkPermissions() — логика инструмента (например, песочница путей)
|
ОДОБРЕНО --> call()
Claude Code поддерживает несколько режимов, которые задают общее поведение:
- default — спрашивает разрешение на потенциально опасные действия. Безопасный выбор по умолчанию.
- plan — агент только планирует и читает, но ничего не меняет. Идеально для разведки в чужом коде.
- acceptEdits — автоматически принимает правки файлов, но всё ещё спрашивает про команды.
- bypassPermissions — без вопросов (опасно, только для изолированных окружений вроде контейнеров).
Warning
Режим bypassPermissions даёт агенту полную свободу. Используйте его только в песочнице/контейнере, где нечего сломать. Никогда не запускайте его на рабочей машине с доступом к продакшену.
Правила позволяют один раз описать, что разрешено без вопросов, а что запрещено всегда:
{
"permissions": {
"allow": [
"Bash(npm run test:*)",
"Read(src/**)"
],
"deny": [
"Bash(rm -rf *)",
"Read(.env)"
]
}
}Так вы разрешаете тесты и чтение исходников, но навсегда запрещаете разрушительные команды и чтение секретов.
Слэш-команды (/command) — быстрый способ управлять сессией. Их около 80; вот категории и самые полезные:
| Категория | Команды | Что делают |
|---|---|---|
| Сессия | /clear, /compact, /resume, /cost |
управление контекстом и историей |
| Проект | /init, /memory, /review |
память проекта и ревью |
| Модель | /model, /config |
выбор модели и настройки |
| Планирование | /plan |
вход в режим планирования |
| Агенты | /agents |
управление суб-агентами |
| MCP | /mcp |
статус MCP-серверов |
| Аутентификация | /login, /logout |
вход и выход |
Можно создавать собственные команды — это просто markdown-файлы в .claude/commands/. Например, файл .claude/commands/test.md:
Запусти все тесты, найди упавшие и предложи исправления.
Формат ответа: сначала список упавших тестов, потом по каждому — причина и фикс.Теперь в сессии команда /test выполнит этот сценарий. Так вы кодифицируете повторяющиеся задачи команды.
Хуки — это ваши собственные shell-команды, которые Claude Code запускает в определённые моменты жизненного цикла. Они позволяют вставить свою логику, не трогая код агента.
| Хук | Когда срабатывает | Типичное применение |
|---|---|---|
PreToolUse |
перед вызовом инструмента | заблокировать опасную команду, залогировать |
PostToolUse |
после вызова инструмента | автоформатирование, линтинг |
UserPromptSubmit |
при отправке промпта | инъекция контекста, аудит |
Stop |
при завершении ответа | уведомления, отчёты |
Пример: автоматически прогонять форматтер после каждой правки файла. В settings.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "prettier --write \"$CLAUDE_FILE_PATHS\"" }
]
}
]
}
}Теперь любой файл, который агент изменил, автоматически проходит через Prettier — без единого напоминания.
Настройки читаются с приоритетом (нижние переопределяют верхние):
~/.claude/settings.json — глобальные, для всех проектов
<project>/.claude/settings.json — настройки проекта (в git, для команды)
<project>/.claude/settings.local.json — локальные, только ваши (в .gitignore)
Tip
Общекомандные правила кладите в .claude/settings.json и коммитьте в репозиторий — так вся команда получает одинаковое поведение агента. Личные предпочтения — в settings.local.json.
MCP (Model Context Protocol) — открытый протокол, который позволяет подключать к агенту внешние источники данных и инструменты: базы данных, трекеры задач, API, файловые системы. Это способ расширять возможности агента, не меняя его самого.
MCP-АРХИТЕКТУРА
MCPConnectionManager
├── Обнаружение серверов (из settings.json)
│ ├── stdio — запуск дочернего процесса
│ ├── sse — HTTP EventSource
│ ├── http — Streamable HTTP
│ └── ws — WebSocket
│
├── Жизненный цикл клиента
│ ├── connect -> initialize -> список инструментов
│ ├── вызовы через обёртку MCPTool
│ └── переподключение с backoff
│
└── Регистрация инструментов
├── именование: mcp__<сервер>__<инструмент>
├── схема подтягивается с сервера динамически
└── права проходят через ту же систему Permissions
Чтобы дать агенту доступ к файловой системе через официальный MCP-сервер, добавьте в конфиг:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir"]
}
}
}После перезапуска инструменты сервера появятся под именами вроде mcp__filesystem__read_file. Проверить статус подключений можно командой /mcp.
Note
Инструменты MCP проходят ту же проверку прав, что и встроенные. Внешний сервер не может обойти вашу систему разрешений — он просто добавляет новые инструменты в общий пул.
Когда задача большая, её выгодно разбить и делегировать. Каждый суб-агент получает свежий контекст, поэтому главный диалог остаётся чистым, а подзадача решается изолированно.
ГЛАВНЫЙ АГЕНТ
|
┌──┴────────────┬───────────────┐
v v v
FORK-АГЕНТ УДАЛЁННЫЙ IN-PROCESS
дочерний АГЕНТ напарник
процесс через мост тот же процесс
свежий msgs[] изолирован общее состояние
РЕЖИМЫ ЗАПУСКА:
default — в процессе, общий диалог
fork — дочерний процесс, свежий messages[], общий файловый кэш
worktree — изолированный git worktree + fork
remote — мост к удалённому Claude Code / контейнеру
СВЯЗЬ:
SendMessageTool — сообщения между агентами
TaskCreate/Update — общая доска задач
TeamCreate/Delete — управление жизненным циклом команды
Зачем это нужно? Представьте задачу «отрефактори модуль авторизации и обнови тесты». Главный агент может поручить одному суб-агенту исследование кода, другому — написание тестов, а сам собрать результаты. Каждый работает в своём контексте и не «загрязняет» общий диалог лишними деталями.
Можно описать специализированного агента в .claude/agents/. Например, reviewer.md:
---
name: reviewer
description: Строгий ревьюер кода. Ищет баги, проблемы безопасности и стиля.
tools: Read, Grep, Glob
---
Ты — опытный ревьюер. Проверяй код на баги, уязвимости и нарушения стиля.
Не предлагай правки без обоснования. Будь конкретным и краток.Обратите внимание: этому агенту выданы только read-only инструменты — он может анализировать, но не менять код. Это безопасный паттерн для ревью.
Контекстное окно не бесконечно. Когда токены заканчиваются — старые сообщения сжимаются, чтобы освободить место, но не потерять суть.
БЮДЖЕТ КОНТЕКСТНОГО ОКНА
┌─────────────────────────────────────────────┐
│ Системный промпт (инструменты, права, CLAUDE.md) │
├─────────────────────────────────────────────┤
│ История диалога │
│ [сжатое резюме старых сообщений] │
│ --- граница сжатия --- │
│ [свежие сообщения — полная детализация] │
├─────────────────────────────────────────────┤
│ Текущий ход (запрос + ответ) │
└─────────────────────────────────────────────┘
ТРИ СТРАТЕГИИ СЖАТИЯ:
autoCompact — при превышении порога токенов
суммаризирует старые сообщения отдельным вызовом API
snipCompact — удаляет «мёртвые» сообщения и устаревшие маркеры
contextCollapse — реструктурирует контекст для эффективности
ПОТОК СЖАТИЯ:
messages[] --> взять сообщения после границы сжатия
|
v
старые сообщения --> Claude API (суммаризация) --> сжатое резюме
|
v
[резюме] + [граница сжатия] + [свежие сообщения]
Сжатие происходит автоматически, но вы можете запустить его вручную командой /compact — например, перед сменой темы, чтобы «подчистить» контекст и сэкономить токены.
Tip
Если ответы стали «плыть» и агент забывает начало сессии — это сигнал, что контекст переполнен. Сделайте /compact, а для совсем новой задачи — /clear.
Claude Code не грузит все знания в системный промпт (это дорого и раздувает контекст). Вместо этого он подгружает их лениво, когда нужно.
- CLAUDE.md — файлы памяти, читаются по мере необходимости для каждой директории. Кладите сюда правила проекта, стиль кода, команды сборки, важные заметки.
- SkillTool — навыки инжектятся через
tool_result, а не в системный промпт, экономя контекст. - Директория с навыками/заметками — хранилище знаний, доступное агенту по требованию.
Файлы памяти складываются по уровням, от общего к частному:
~/.claude/CLAUDE.md — личные правила для всех проектов
<project>/CLAUDE.md — правила проекта (в git, для команды)
<project>/<subdir>/CLAUDE.md — правила для конкретной подпапки
# Проект: My App
## Стек
- Backend: Node.js + Fastify
- Frontend: React + Vite
- БД: PostgreSQL
## Команды
- \`npm run dev\` — запуск в разработке
- \`npm test\` — тесты (обязательно после изменений)
- \`npm run lint\` — проверка стиля
## Правила
- Используй TypeScript строго, без \`any\`.
- Все новые эндпоинты покрывай тестами.
- Не трогай файлы в \`legacy/\` без явной просьбы.Tip
Держите CLAUDE.md коротким и конкретным. Это не документация проекта, а «шпаргалка для агента»: команды, соглашения, запреты. Длинные файлы съедают контекст и снижают качество.
Режим планирования — это когда агент сначала думает и составляет план, и только потом действует. В этом режиме он читает код и рассуждает, но ничего не меняет, пока вы не одобрите план.
ОБЫЧНЫЙ РЕЖИМ: запрос -> сразу правки -> результат
PLAN MODE: запрос -> исследование -> ПЛАН -> [ваше одобрение] -> правки
Как включить: команда /plan или запуск с флагом. Плюсы:
- Безопасность — агент ничего не сломает, пока вы не согласитесь.
- Прозрачность — вы видите намерения до действий.
- Качество — «агент без плана дрейфует»; явный план заметно повышает долю успешно решённых задач.
Tip
Для незнакомого или критичного кода всегда начинайте с plan mode. Прочитайте план, поправьте, если агент понял задачу не так, и только потом разрешайте выполнение.
Каждая сессия пишется на диск в виде журнала — это позволяет восстановить работу после перезапуска или сбоя.
ХРАНИЛИЩЕ СЕССИЙ
~/.claude/projects/<hash>/sessions/
└── <session-id>.jsonl — журнал только на дозапись
├── {"type":"user",...}
├── {"type":"assistant",...}
└── {"type":"system","subtype":"compact_boundary",...}
ВОССТАНОВЛЕНИЕ:
--continue — последняя сессия в текущей папке
--resume <id> — конкретная сессия
--fork-session — новый id, копия истории
Стратегия записи продумана под надёжность: пользовательские сообщения пишутся синхронно (чтобы точно не потерять при сбое), а ответы ассистента — «выстрелил и забыл», с сохранением порядка. Формат JSONL (по объекту на строку) удобно читать и парсить.
Практика: прервали работу — вернитесь командой claude --continue. Нужна конкретная старая сессия — claude --resume <id> или интерактивно через /resume.
Это ядро гайда. Каждый следующий механизм строится на предыдущем — так плоский цикл превращается в продакшн-агент.
| № | Механизм | Суть одной фразой |
|---|---|---|
| 1 | Цикл | «одного цикла и Bash достаточно»: while-true зовёт API, проверяет stop_reason, выполняет инструменты |
| 2 | Диспетчеризация инструментов | добавить инструмент = добавить один обработчик; цикл не меняется |
| 3 | Планирование | агент без плана дрейфует; сначала список шагов, потом выполнение |
| 4 | Суб-агенты | большие задачи дробим; у каждого суб-агента свежий контекст |
| 5 | Знания по требованию | грузим знания, когда они нужны, через tool_result |
| 6 | Сжатие контекста | контекст переполняется — освобождаем место (три стратегии) |
| 7 | Персистентные задачи | большие цели → мелкие задачи → на диск, с зависимостями и статусами |
| 8 | Фоновые задачи | медленные операции в фоне, агент продолжает думать |
| 9 | Команды агентов | слишком велико для одного — делегируем напарникам с почтовыми ящиками |
| 10 | Протоколы команд | единый паттерн запрос-ответ управляет всей коммуникацией |
| 11 | Автономные агенты | напарники сами сканируют и забирают задачи, без ручного назначения |
| 12 | Изоляция worktree | каждый работает в своей директории (git worktree), связанной по id |
Главная идея этой таблицы: сложность агента — не в цикле, а в обвязке вокруг него. Цикл остаётся тем же с самого первого раздела. Всё, что делает агент «продакшн-грейд» — это 11 слоёв поверх одной простой петли.
Агент без наблюдаемости — чёрный ящик: непонятно, почему он принял решение, где потратил токены и на каком шаге сломался. Продакшн-агент логирует каждый виток цикла структурированно.
ЧТО ТРЕЙСИТЬ НА КАЖДОМ ВИТКЕ ЦИКЛА
─────────────────────────────────
запрос к API → модель, размер контекста (токены in), latency
ответ модели → stop_reason, токены out, стоимость витка
вызов инструмента → имя, аргументы (без секретов!), длительность, успех/ошибка
проверка прав → решение (allow/deny), какое правило сработало
сжатие контекста → до/после (токены), какая стратегия
СПАН-ИЕРАРХИЯ (OpenTelemetry-совместимо)
session
└── turn (один ход пользователя)
└── api_call (виток цикла)
├── tool_use: bash
└── tool_use: read_file
Три уровня наблюдаемости, которые стоит завести сразу: логи (структурный JSONL по событиям), метрики (токены/стоимость/latency/доля ошибок инструментов) и трейсы (сквозной путь одного запроса через все витки и инструменты).
Tip
Логируйте session_id и turn_id в каждой записи. Тогда любой инцидент («агент удалил не тот файл») восстанавливается по журналу за секунды: видно точный инструмент, аргументы и правило прав, которое его пропустило.
Токены — это деньги и латентность. В длинной агентной сессии значительная доля стоимости приходится на повторную отправку истории на каждом витке цикла. Понимание, куда уходят токены, экономит кратно.
КУДА УХОДЯТ ТОКЕНЫ (типичная сессия)
────────────────────────────────────
системный промпт + описания инструментов ~ фикс. оверхед КАЖДОГО витка
история диалога растёт линейно с шагами
вывод инструментов (bash, файлы) часто ГЛАВНЫЙ пожиратель
ответы модели обычно малы
ПРАВИЛО: input-токены >> output-токены. Оптимизируйте ВВОД.
| Приём | Эффект |
|---|---|
| Prompt caching системного промпта | не платите за статичную часть повторно |
| Обрезка вывода инструментов | не суйте в контекст тысячи строк лога — только хвост/греп |
Своевременный /compact |
линейный рост истории → плоское резюме |
Узкие Grep/Glob вместо чтения целиком |
читайте только релевантные строки |
| Дешёвая модель для суб-агентов | рутину (сортировка, извлечение) — на модель попроще |
Tip
Команда /cost показывает разбивку по сессии. Если стоимость растёт быстрее, чем сложность задачи — почти всегда виноват раздутый вывод инструмента, попавший в историю. Фильтруйте вывод до того, как он вернётся в messages[].
Системный промпт Claude Code огромен: описания 40+ инструментов, права, CLAUDE.md. Отправлять его заново на каждом витке — расточительно. Кэширование промптов позволяет один раз «прогреть» стабильный префикс и переиспользовать его.
БЕЗ КЭША: [СИСТЕМА+ИНСТРУМЕНТЫ][история][ход] ← платим за всё каждый виток
С КЭШЕМ: [====кэш-хит====][история][ход] ← платим лишь за новое
ГРАНИЦЫ КЭША (cache breakpoints), от стабильного к изменчивому:
1. системный промпт + определения инструментов (меняется редко) ← кэш
2. CLAUDE.md / контекст проекта (стабильно) ← кэш
3. ранняя история диалога (растёт) ← кэш
4. свежие сообщения (каждый ход) — без кэша
Ключевой принцип: кэш работает по префиксу. Всё стабильное держите в начале, всё изменчивое — в конце. Одно изменение в начале инвалидирует весь кэш ниже.
Important
Порядок важнее всего. Если вставлять «текущую дату» или случайный id в самое начало системного промпта — кэш не сработает никогда. Динамику держите ближе к концу контекста.
Обычные юнит-тесты проверяют детерминированный код. Агент недетерминирован: та же задача может решиться разными путями. Поэтому его оценивают не по «точному выводу», а по достижению цели на наборе сценариев (eval-набор).
ПИРАМИДА ТЕСТИРОВАНИЯ АГЕНТА
───────────────────────────
┌───────────────┐
│ End-to-End │ «почини баг X в репо» → тест зелёный?
│ сценарии │ (мало, дорого, самые ценные)
├───────────────┤
│ Инструменты │ каждый tool: валидный ввод → ожидаемый эффект
│ (детермин.) │ (много, дёшево, быстро)
├───────────────┤
│ Проверки прав │ deny-правило реально блокирует rm -rf?
└───────────────┘
Как оценивать вероятностный результат: задайте проверяемый критерий успеха (тесты проходят, файл содержит нужное, команда вернула 0), гоняйте каждый сценарий несколько раз и смотрите долю успеха (pass@k), а сложные случаи отдавайте на LLM-as-judge с чёткой рубрикой.
| Что тестировать | Как |
|---|---|
| Отдельные инструменты | обычные юнит-тесты (детерминированно) |
| Ворота прав | сценарии allow/deny с проверкой блокировки |
| Поведение агента | eval-набор задач + автоматическая проверка результата |
| Регрессии | прогон eval-набора на каждый релиз промпта/модели |
Warning
Не оценивайте агента «на глаз» после ручной проверки пары задач. Меняете системный промпт или модель — прогоняйте весь eval-набор. Улучшение на одном примере часто ломает пять других.
Как только агент читает внешние данные (веб-страницы, файлы, вывод команд, тикеты), появляется главная угроза — prompt injection: во внешнем тексте спрятаны инструкции, которые агент может принять за команды пользователя.
МОДЕЛЬ УГРОЗ КОДИНГ-АГЕНТА
──────────────────────────
1. Prompt injection вредный текст в файле/вебе → «выполни rm -rf», «слей .env»
2. Эксфильтрация секреты в контекст → отправка наружу через bash/веб
3. Опасные команды деструктив (rm, drop table, git push --force)
4. Выход за периметр доступ к путям вне проекта, к продакшену
ГРАНИЦА ДОВЕРИЯ
[ инструкции пользователя ] = доверенные
[ вывод инструментов/файлов/веба ] = ДАННЫЕ, не инструкции
Практическая защита выстраивается слоями: права и sandbox (deny на rm -rf, чтение .env, запись вне проекта), изоляция секретов от контекста агента, человек в цикле на необратимых действиях и трактовка любого внешнего текста как данных, а не команд.
| Слой | Что делает |
|---|---|
Правила прав (deny) |
глухая блокировка опасного, что бы ни «попросила» модель |
| Sandbox путей | checkPermissions() не пускает за пределы проекта |
| Изоляция секретов | ключи не попадают в messages[] вообще |
| Human-in-the-loop | подтверждение на деструктив и сетевые операции |
Warning
Никогда не давайте агенту одновременно и доступ к секретам, и возможность отправлять данные наружу без подтверждения. Это классический канал эксфильтрации: инъекция в прочитанном файле → чтение .env → curl на чужой сервер.
Реальный мир ненадёжен: API отвечает 429/500, сеть отваливается, команда зависает. Продакшн-агент не должен падать от первой же ошибки — он восстанавливается.
ЭКСПОНЕНЦИАЛЬНЫЙ BACKOFF С JITTER
─────────────────────────────────
попытка 1 → ошибка 429 → ждём ~1s
попытка 2 → ошибка 429 → ждём ~2s (+ случайный jitter)
попытка 3 → ошибка 500 → ждём ~4s
попытка 4 → успех ✓
(после N попыток — аккуратно сдаёмся)
ЧТО РЕТРАИТЬ, А ЧТО НЕТ
429 / 500 / 503 / таймаут → ретрай (временное)
400 / 401 / 403 → НЕ ретраить (ошибка запроса/прав)
Базовые приёмы устойчивости: ретрай с backoff только на транзиентные ошибки, таймауты на каждый вызов инструмента (зависший bash не должен вешать сессию), идемпотентность повторяемых действий и graceful degradation — при отказе инструмента вернуть tool_result с ошибкой, чтобы агент попробовал другой путь, а не рухнул.
Tip
Отказ инструмента — не конец цикла, а сигнал модели. Возвращайте понятную ошибку в tool_result («команда превысила таймаут 30с») — агент часто сам сообразит обходной путь.
Отзывчивость агента держится на двух вещах: стриминге (пользователь видит ответ по мере генерации, а не через 30 секунд тишины) и параллельном выполнении безопасных инструментов.
ПАРАЛЛЕЛЬНОЕ ВЫПОЛНЕНИЕ ИНСТРУМЕНТОВ
────────────────────────────────────
модель вернула 3 вызова за один виток:
read_file(a) ┐
read_file(b) ├─ isConcurrencySafe? → да → запускаем ВМЕСТЕ
grep(x) ┘
vs
write_file(c) → меняет состояние → строго ПОСЛЕДОВАТЕЛЬНО
ПОТОК СТРИМИНГА
API (SSE) → дельты текста → сразу в терминал
→ блок tool_use собирается целиком → затем выполняется
Правило безопасности параллелизма — тот самый флаг isConcurrencySafe() из раздела про инструменты: read-only операции (чтение, поиск) летят пачкой и резко ускоряют разведку по кодовой базе, а всё, что меняет файлы или состояние, сериализуется, чтобы не создавать гонок.
Tip
Самый дешёвый прирост скорости — распараллелить чтение и поиск. Когда агент исследует незнакомый проект, десяток Read/Grep параллельно превращают минуты ожидания в секунды.
Чтобы прочувствовать цикл, соберём его в ~20 строках на псевдо-Python. Это ядро, которое масштабируется до всего Claude Code.
messages = [{"role": "user", "content": prompt}]
while True:
response = claude_api(messages, tools=TOOLS)
messages.append(response.message)
if response.stop_reason != "tool_use":
print(response.text) # финальный ответ
break
for call in response.tool_calls:
if not check_permission(call): # ворота прав
result = {"error": "denied"}
else:
result = TOOLS[call.name](call.input) # выполнить инструмент
messages.append({"role": "tool", "content": result})
# цикл повторяется — модель видит результаты и решает, что дальшеimport subprocess
def tool_read_file(args):
with open(args["path"]) as f:
return {"content": f.read()}
def tool_bash(args):
out = subprocess.run(args["cmd"], shell=True, capture_output=True, text=True)
return {"stdout": out.stdout, "stderr": out.stderr, "code": out.returncode}
TOOLS = {"read_file": tool_read_file, "bash": tool_bash}Уже с этими двумя инструментами (чтение файла + запуск команды) агент может исследовать проект, запускать тесты и чинить ошибки. Именно так устроен любой кодинг-агент в своей основе.
- Проверку прав перед вызовом (мы уже заложили функцию проверки).
- Планирование — todo-лист, который агент ведёт сам.
- Сжатие истории при переполнении контекста.
- Запись в JSONL для восстановления после сбоя.
- Суб-агентов для крупных подзадач с чистым контекстом.
Пройдя эти пять шагов, вы повторите путь от учебного скрипта до архитектуры уровня Claude Code.
Теперь соберём тот же цикл, но уже с настоящим SDK Anthropic и корректными схемами инструментов. Это полностью рабочий скелет — добавьте свой API-ключ и запускайте.
import subprocess, json
from anthropic import Anthropic
client = Anthropic() # ключ берётся из ANTHROPIC_API_KEY
# 1) Описываем инструменты для модели (JSON Schema)
TOOL_SCHEMAS = [
{
"name": "read_file",
"description": "Прочитать текстовый файл по пути и вернуть содержимое.",
"input_schema": {
"type": "object",
"properties": {"path": {"type": "string"}},
"required": ["path"],
},
},
{
"name": "bash",
"description": "Выполнить shell-команду и вернуть stdout/stderr/код возврата.",
"input_schema": {
"type": "object",
"properties": {"cmd": {"type": "string"}},
"required": ["cmd"],
},
},
]
# 2) Реализация инструментов
def read_file(path):
with open(path, encoding="utf-8") as f:
return f.read()[:10_000] # обрезаем, чтобы не раздуть контекст
def bash(cmd):
r = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=30)
tail = lambda s: s[-2000:] # отдаём только хвост длинного вывода
return json.dumps({"stdout": tail(r.stdout), "stderr": tail(r.stderr), "code": r.returncode})
IMPL = {"read_file": lambda a: read_file(a["path"]),
"bash": lambda a: bash(a["cmd"])}
# 3) Ворота прав: опасное — блокируем, остальное — спрашиваем
DENY = ("rm -rf", "git push --force", ":(){", "mkfs", "dd if=")
def check_permission(name, args):
if name == "bash":
cmd = args.get("cmd", "")
if any(bad in cmd for bad in DENY):
return False
return input(f"Выполнить `{cmd}`? [y/N] ").strip().lower() == "y"
return True # чтение безопасно
# 4) Главный агентный цикл
def run(prompt):
messages = [{"role": "user", "content": prompt}]
while True:
resp = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=2048,
tools=TOOL_SCHEMAS,
messages=messages,
)
messages.append({"role": "assistant", "content": resp.content})
if resp.stop_reason != "tool_use":
print(next(b.text for b in resp.content if b.type == "text"))
return
results = []
for block in resp.content:
if block.type != "tool_use":
continue
if not check_permission(block.name, block.input):
out, err = "Отказано пользователем", True
else:
try:
out, err = IMPL[block.name](block.input), False
except Exception as e:
out, err = f"Ошибка инструмента: {e}", True
results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": str(out),
"is_error": err,
})
messages.append({"role": "user", "content": results})
if __name__ == "__main__":
run("Найди все файлы .py в src/, посчитай строки и покажи самый большой")Important
Обратите внимание на четыре продакшн-детали, которых не было в псевдокоде: таймаут на bash, обрезку вывода (tail) для экономии токенов, флаг is_error в tool_result (агент понимает, что инструмент упал, и пробует иначе) и блок-лист опасных команд, который срабатывает раньше запроса к пользователю.
Запрос: «Найди все файлы .py в src/, посчитай строки и покажи самый большой». Вот что происходит виток за витком:
ВИТОК 1
-> API: messages=[user], tools=[read_file, bash]
<- stop_reason=tool_use -> bash("find src -name '*.py'")
[права] команда безопасна, пользователь: y
-> tool_result: "src/app.py\nsrc/db.py\nsrc/utils.py"
ВИТОК 2
<- stop_reason=tool_use -> bash("wc -l src/app.py src/db.py src/utils.py")
[права] y
-> tool_result: "120 src/app.py\n64 src/db.py\n38 src/utils.py"
ВИТОК 3
<- stop_reason=end_turn (инструменты больше не нужны)
<- текст: "Найдено 3 файла. Самый большой — src/app.py (120 строк)."
Три витка, два вызова инструментов, один текстовый ответ. Модель сама решила: сначала найти файлы, потом посчитать строки, потом сделать вывод. Мы не программировали эту последовательность — она следствие цикла.
/init # сгенерировать CLAUDE.md
"Опиши архитектуру проекта и точки входа"
"Где обрабатываются HTTP-запросы?"
"Запусти тесты, найди упавший, объясни причину и предложи фикс"
# просмотрите план, одобрите правку
/plan # включить режим планирования
"Отрефактори модуль auth: раздели на слои, сохрани поведение"
# читаете план -> одобряете -> агент правит -> прогоняет тесты
/review
"Проверь мои незакоммиченные изменения на баги и стиль"
claude -p "Обнови CHANGELOG по коммитам с последнего тега" --output-format json"Вот стектрейс из прода (вставляю ниже). Найди причину в коде,
объясни цепочку вызовов и предложи минимальный фикс. Не меняй ничего,
пока я не подтвержу."
# агент: Grep по имени исключения -> Read виновных файлов -> гипотеза -> фикс
Ключевое здесь — фраза «не меняй ничего, пока не подтвержу». Она удерживает агента в режиме анализа, и вы получаете разбор до правок.
/plan
"Переименуй функцию `getUser` в `fetchUser` во всём проекте:
обнови объявление, все вызовы и тесты. Не трогай строки в комментариях
и логах, если это не идентификатор."
# план -> одобрение -> Grep находит все вхождения -> Edit по каждому -> прогон тестов
Tip
Для рискованных массовых правок всегда связка «/plan + частый коммит». Сделайте git commit до запуска — если результат не понравится, git reset --hard откатит всё одной командой.
"Покрой тестами модуль `src/pricing.py`. Сначала прочитай его,
перечисли граничные случаи (нули, отрицательные, пустые списки),
потом напиши тесты на pytest и запусти их."
Агент сначала проговаривает граничные случаи (вы можете поправить список), и только потом пишет код — так тесты получаются осмысленными, а не формальными.
# Каждое утро в 9:00 — сводка ошибок за сутки
claude -p "Прочитай logs/app.log, сгруппируй ошибки за последние 24ч \
по типу, выдели топ-3 по частоте и оцени серьёзность. Формат: markdown." \
--output-format json | ./post-to-slack.sh/plan
"Обнови библиотеку X с версии 1.x до 2.x. Прочитай CHANGELOG об ломающих
изменениях, найди затронутые места в коде, обнови их и прогони тесты.
Если тесты падают — чини, пока не станут зелёными."
# агент работает циклом: правка -> тест -> анализ падения -> правка ...
Это демонстрирует главную силу агента над обычным автодополнением: петля обратной связи. Он не просто пишет код — он запускает тесты, видит результат и итерирует до успеха.
Пять сквозных примеров, где мы не просто даём команду, а собираем настоящий артефакт: свою слэш-команду, хук, суб-агента, MCP-интеграцию и полную сессию отладки. Каждый пример можно повторить у себя.
Задача: чтобы вместо длинного промпта достаточно было набрать /review-pr. Создаём файл .claude/commands/review-pr.md:
Проверь изменения в текущей ветке относительно main.
Шаги:
1. Выполни `git diff main...HEAD` и прочитай изменения.
2. Для каждого файла оцени: баги, утечки ресурсов, edge-cases, стиль.
3. Проверь, покрыты ли новые ветки кода тестами.
Формат ответа:
- **Блокеры** (чинить обязательно) — список с файлом и строкой.
- **Замечания** (желательно) — список.
- **Хорошо** — что сделано правильно.
Аргумент $ARGUMENTS — необязательный фокус ревью (например, "безопасность").Теперь в сессии:
/review-pr безопасность
# агент подставит "безопасность" в $ARGUMENTS и сделает ревью с этим акцентом
Tip
Плейсхолдер $ARGUMENTS подставляет всё, что вы написали после имени команды. Так одна команда покрывает и общий ревью, и узкий фокус — без дублирования файлов.
Задача: перед любой записью в файл проверять, не попадает ли туда секрет. Это защитный PreToolUse-хук. В .claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{ "type": "command", "command": "python .claude/hooks/no_secrets.py" }
]
}
]
}
}Сам скрипт .claude/hooks/no_secrets.py читает данные хука из stdin и возвращает решение:
import sys, json, re
data = json.load(sys.stdin) # что агент собирается писать
content = json.dumps(data.get("tool_input", {}))
PATTERNS = [
r"sk-[A-Za-z0-9]{20,}", # API-ключи вида sk-...
r"AKIA[0-9A-Z]{16}", # AWS access key
r"-----BEGIN (RSA )?PRIVATE KEY", # приватные ключи
]
for p in PATTERNS:
if re.search(p, content):
# ненулевой код + сообщение в stderr = БЛОКИРОВКА операции
print(f"Заблокировано: похоже на секрет ({p})", file=sys.stderr)
sys.exit(2)
sys.exit(0) # чисто — разрешаем записьТеперь, даже если агент по ошибке попытается вписать ключ в файл, хук перехватит операцию до записи и вернёт агенту сообщение об ошибке — тот попробует другой путь.
Warning
Код возврата 2 в PreToolUse-хуке означает «блокировать и сообщить модели». Код 0 — «всё чисто, продолжай». Это простой и надёжный контракт для собственных проверок безопасности.
Задача: выделить написание и прогон тестов в отдельного агента со своим чистым контекстом. Файл .claude/agents/tester.md:
---
name: tester
description: Пишет и запускает тесты. Вызывать, когда нужно покрытие или проверка.
tools: Read, Grep, Glob, Bash
---
Ты — инженер по тестированию. Твоя задача — довести тесты до зелёного.
Алгоритм:
1. Прочитай целевой модуль и пойми его контракт.
2. Составь список сценариев: happy-path, границы, ошибки.
3. Напиши тесты в стиле проекта (посмотри существующие тесты).
4. Запусти их. Если красные — чини тест или укажи на баг в коде.
5. Верни краткий отчёт: сколько тестов, что покрыто, что осталось.
Не рефактори продакшн-код без явной причины — только тесты.Главный агент вызовет tester одной задачей, тот отработает в своём контексте и вернёт отчёт — основной диалог не засорится сотней строк вывода pytest.
"Делегируй суб-агенту tester покрытие модуля src/cart.py"
# главный агент -> Agent(tester, "покрой src/cart.py") -> получает отчёт
Задача: дать агенту читать схему и делать безопасные запросы к Postgres. Используем готовый MCP-сервер. В .claude/settings.json:
{
"mcpServers": {
"postgres": {
"command": "npx",
"args": [
"-y", "@modelcontextprotocol/server-postgres",
"postgresql://readonly_user@localhost:5432/mydb"
]
}
}
}После перезапуска проверяем подключение и работаем:
/mcp # убедиться, что postgres: connected
"Покажи схему таблицы orders и напиши SQL: топ-5 клиентов по сумме за 2024"
# инструмент mcp__postgres__query выполнит запрос и вернёт результат
Important
Подключайте БД под readonly-пользователем. MCP-инструменты проходят ту же систему прав, но принцип наименьших привилегий на стороне БД — ваша последняя линия обороны: даже ошибочный DELETE просто не выполнится.
Соберём всё вместе. Тест падает, разбираемся с нуля.
$ claude
> Тест test_discount_applies_once падает. Разберись и почини.
[агент] /plan
Grep "test_discount_applies_once" -> tests/test_cart.py:42
Read tests/test_cart.py (сценарий: скидка не должна применяться дважды)
Read src/cart.py -> функция apply_discount()
Гипотеза: флаг discount_applied сбрасывается при каждом add_item()
ПЛАН:
1. Перенести сброс флага из add_item() в checkout()
2. Прогнать весь набор тестов cart
[ожидаю одобрения]
> да, действуй
[агент] Edit src/cart.py (переносит сброс флага)
Bash "pytest tests/test_cart.py -q"
-> 14 passed
Готово: причина была в преждевременном сбросе флага в add_item().
Все 14 тестов cart зелёные.
Разберём, что здесь сработало из всего гайда: /plan (раздел 16) удержал агента от слепых правок, Grep/Read (раздел 8) локализовали проблему, ворота прав (раздел 9) дали вам точку контроля перед Edit, а петля правка -> тест -> результат (базовый цикл, раздел 5) довела задачу до зелёного. Один пример — почти вся архитектура в действии.
Tip
Замечайте паттерн «сначала локализуй, потом чини». Хороший промпт для отладки почти всегда просит агента сначала найти и объяснить причину, и только потом править. Это резко снижает долю «правок наугад».
- Начинайте с
/init— дайте агентуCLAUDE.mdс контекстом проекта. - Используйте plan mode для незнакомого и критичного кода.
- Держите задачи узкими — «почини этот тест» лучше, чем «исправь все баги».
- Коммитьте часто — так легко откатить неудачную правку агента.
- Настройте хуки — авто-форматирование и линтинг после правок экономят время.
- Запрещайте опасное явно —
deny-правила дляrm -rf, чтения.envи т.п.
bypassPermissionsна рабочей машине — только в изолированной песочнице.- Огромный
CLAUDE.md— он съедает контекст; держите его коротким. - Одна бесконечная сессия — периодически делайте
/clearили/compact. - Слепое одобрение всего — читайте, что агент собирается запустить.
- Секреты в промптах и файлах — не давайте агенту доступ к ключам и паролям.
| Симптом | Вероятная причина | Что делать |
|---|---|---|
| Агент «забывает» начало сессии | переполнен контекст | /compact или /clear |
| Ответы стали медленными/дорогими | раздутая история | /compact, начните новую сессию |
| Постоянно спрашивает разрешение | нет правил в settings | добавьте allow-правила |
| Инструмент MCP не виден | сервер не поднялся | проверьте /mcp, перезапустите |
| Правит не те файлы | нет контекста проекта | сделайте /init, уточните задачу |
command not found: claude |
не в PATH | переустановите глобально через npm |
| Агент делает лишнее | задача слишком широкая | сузьте формулировку, включите plan mode |
Tip
Команда /cost покажет, сколько токенов и денег ушло на сессию. Если цифра растёт слишком быстро — почти всегда виноват переполненный контекст.
| Термин | Значение |
|---|---|
| Агент | модель + инструменты + цикл, который крутится до решения задачи |
| Агентный цикл | while-петля: вызов API → проверка stop_reason → выполнение инструментов → повтор |
| Инструмент (tool) | функция, которую модель может вызвать (чтение файла, bash, поиск и т.д.) |
| tool_use / tool_result | запрос модели на вызов инструмента и результат его выполнения |
| stop_reason | поле ответа API: почему модель остановилась (нужен инструмент или готов ответ) |
| Права (permissions) | система «ворот», решающая, можно ли выполнить инструмент |
| Хук (hook) | ваша shell-команда, запускаемая в момент жизненного цикла агента |
| MCP | Model Context Protocol — протокол подключения внешних инструментов |
| Суб-агент | дочерний агент со свежим контекстом для отдельной подзадачи |
| Compact | сжатие/суммаризация старой истории для экономии контекста |
| CLAUDE.md | файл памяти проекта: правила, команды, соглашения |
| Plan mode | режим «сначала план, потом действие» без изменений до одобрения |
| Worktree | отдельная рабочая директория git для изоляции параллельной работы |
| REPL | интерактивный режим (Read-Eval-Print Loop) в терминале |
| Headless | неинтерактивный запуск (в скриптах, CI) через флаг -p |
| Харнесс (harness) | «обвязка» вокруг цикла: права, ретраи, сжатие, персистентность, логи — всё, что делает агент продакшн-грейд (раздел 5A, 18) |
Нужен ли платный тариф? Для работы Claude Code нужен доступ к API/аккаунту Anthropic. Проверьте актуальные условия на сайте Anthropic.
Можно ли использовать без интернета? Нет — модель работает через API Anthropic. Локально хранятся только сессии и настройки.
Где хранятся мои данные сессий? Локально, в ~/.claude/projects/. Это обычные JSONL-файлы, их можно читать и парсить.
Как задать правила проекта? Создайте файл CLAUDE.md в корне репозитория (или запустите /init).
Безопасно ли давать агенту доступ к терминалу? Да, если пользоваться системой прав: держите режим default, добавьте deny-правила для опасных команд, а bypassPermissions используйте только в песочнице.
Чем суб-агент отличается от новой сессии? Суб-агент запускается внутри текущей задачи с чистым контекстом и возвращает результат главному агенту, не засоряя основной диалог.
Что делать, если агент пошёл не туда? Прервите его, уточните задачу, при необходимости /clear. Частые коммиты позволяют легко откатить неудачные правки.
Как подключить свою базу данных или API? Через MCP-сервер — см. раздел 12.
- Соберите свой мини-агент по разделу 26 — это лучший способ понять, как всё работает.
- Настройте
CLAUDE.mdи хуки под свой проект — почувствуете разницу в качестве. - Изучите MCP — подключите реальный внешний инструмент.
- Поэкспериментируйте с суб-агентами — опишите ревьюера и тестировщика.
- Прочитайте официальную документацию Anthropic для актуальных деталей конкретной версии.
Понравился гайд? Поставьте ⭐ репозиторию и делитесь с коллегами.
Всё самое нужное в одном месте — держите открытым рядом.
ЧТО ЗА ЗАДАЧА?
|
┌───────────────────────┼───────────────────────┐
v v v
одношаговая? многошаговая? незнакомый/
(спросить, понять) (почини, собери) критичный код?
| | |
v v v
обычный чат обычный агент /plan сначала
или /ask (default права) (только чтение,
| план -> одобрить)
нужны внешние данные?
(БД, API, трекер)
|
v
подключить MCP (раздел 12)
Опасное/необратимое? -> добавь deny-правило в settings.json
Медленная операция? -> запусти в фоне / делегируй суб-агенту
Контекст «поплыл»? -> /compact, для новой темы -> /clear
| Команда | Что делает |
|---|---|
npm install -g @anthropic-ai/claude-code |
установка |
claude |
интерактивный режим (REPL) в текущей папке |
claude "вопрос" |
одноразовый запрос |
claude -p "..." --output-format json |
headless (скрипты, CI) |
claude --continue |
продолжить последнюю сессию |
claude --resume <id> |
вернуться к конкретной сессии |
| Команда | Назначение |
|---|---|
/init |
сгенерировать CLAUDE.md для проекта |
/plan |
режим планирования (сначала план, потом действие) |
/clear · /compact |
очистить · сжать контекст |
/review |
ревью изменений |
/model · /config |
выбор модели · настройки |
/agents · /mcp |
суб-агенты · статус MCP-серверов |
/memory · /cost |
файлы памяти · токены и стоимость |
/resume · /exit |
восстановить сессию · выход |
| Режим | Поведение | Когда |
|---|---|---|
default |
спрашивает про опасное | по умолчанию, безопасно |
plan |
только чтение + план | разведка в чужом коде |
acceptEdits |
правки без вопросов, команды — со спросом | доверенный поток |
bypassPermissions |
без вопросов |
| Путь | Что это |
|---|---|
| ``/.claude/settings.json` | глобальные настройки (все проекты) |
<проект>/.claude/settings.json |
настройки проекта (в git, для команды) |
<проект>/.claude/settings.local.json |
личные (в .gitignore) |
CLAUDE.md |
память проекта: стек, команды, правила |
.claude/commands/*.md |
свои слэш-команды |
.claude/agents/*.md |
свои суб-агенты |
.claude/hooks/* |
скрипты хуков |
{
"permissions": {
"allow": ["Bash(npm run test:*)", "Read(src/**)"],
"deny": ["Bash(rm -rf *)", "Read(.env)", "Bash(git push --force*)"]
}
}| Хук | Когда | Пример |
|---|---|---|
PreToolUse |
до вызова инструмента | блок опасного, проверка секретов |
PostToolUse |
после вызова | автоформат, линтинг |
UserPromptSubmit |
при отправке промпта | инъекция контекста, аудит |
Stop |
при завершении ответа | уведомления, отчёты |
| Слой | Зачем | Раздел |
|---|---|---|
| Сборка входа | промпт + `/команды` + CLAUDE.md | 6, 15 |
| Ворота прав | блок опасного до выполнения | 9 |
| Ретраи/таймауты | пережить 429/500/зависание | 24 |
| Сжатие контекста | не «ослепнуть» при переполнении | 14 |
| Персистентность | продолжить после сбоя | 17 |
| Наблюдаемость | понять, что и почему сделал | 19 |
Tip
Если запомнить только одно: /init в начале проекта, /plan для рискованного, /compact когда «поплыло», и deny-правила для опасного. Этих четырёх привычек хватает для 90% повседневной работы.
Материалы репозитория предназначены только для технического исследования и обучения. Все права на интеллектуальную собственность принадлежат оригинальной компании. При обнаружении нарушения прав свяжитесь с владельцем репозитория для удаления.