05 / 06 · Best Practices

🤖 Eric Buess

Продвинутая агентная инженерия: автогенерируемые карты проекта, agent-scoped hooks, session ID для кеширования токенов и полная observability агентов. Подход для тех кто хочет контролировать AI-агентов на уровне production-систем.

🤖
Eric Buess
Agentic Engineering Educator
⚠️
Частая ошибка новичков: создают один глобальный hook-файл для всех проектов вместо agent-scoped hooks. Глобальные hooks запускаются для каждого агента — в том числе для тех агентов где они не нужны — и добавляют лишний overhead. Eric Buess's подход: hook автоматически определяет контекст текущего агента и применяет только нужную логику. Если у вас больше трёх глобальных hooks — возможно, часть из них должны быть agent-scoped.
🤖 Ключевой принцип

"Project Indexer Hook + Agent-Scoped Hooks = агенты которые знают проект." Агент не должен тратить токены на "понимание" структуры при каждом запуске — hook автоматически генерирует актуальную карту проекта, а agent-scoped hooks несут нужную логику прямо в себе.

💡
Тонкость для опытных: Project Indexer Hook от Eric Buess лучше всего работает когда генерируемый index.md структурирован под задачи агента, а не просто перечисляет файлы. Включайте в него: ключевые точки входа, паттерны именования, расположение тестов, команды запуска и сборки. Агент который получает навигационную карту тратит в 3–5 раз меньше токенов на первичную ориентацию чем агент который читает структуру файлов вручную.
1
Project Indexer Hook — автогенерируемая карта проекта

Одна из самых дорогих операций в начале агентной сессии — "разведка": Claude просматривает файловую структуру, читает ключевые файлы, строит ментальную карту проекта. Для больших проектов это занимает десятки итераций tool calls.

Buess решает это через PreToolUse hook который автоматически генерирует минифицированный index.md при старте каждой сессии:

{
  "hooks": {
    "PreToolUse": [{
      "matcher": ".*",
      "hooks": [{
        "type": "command",
        "command": "node ~/.claude/hooks/project-indexer.js"
      }]
    }]
  }
}

Скрипт project-indexer.js рекурсивно обходит файлы проекта и создаёт минимальный манифест:

const fs = require('fs');
const path = require('path');

// Сканировать только важные директории
const SCAN_DIRS = ['app', 'src', 'tests', 'database'];
const SKIP_DIRS = ['vendor', 'node_modules', 'storage', '.git'];

function scanDirectory(dir, depth = 0) {
  if (depth > 3) return ''; // Максимум 3 уровня вложенности
  const entries = fs.readdirSync(dir, { withFileTypes: true });
  let result = '';

  for (const entry of entries) {
    if (SKIP_DIRS.includes(entry.name)) continue;
    const indent = '  '.repeat(depth);
    if (entry.isDirectory()) {
      result += `${indent}📁 ${entry.name}/\n`;
      result += scanDirectory(path.join(dir, entry.name), depth + 1);
    } else if (entry.name.endsWith('.php') || entry.name.endsWith('.ts')) {
      result += `${indent}📄 ${entry.name}\n`;
    }
  }
  return result;
}

const index = `# Project Index (auto-generated ${new Date().toISOString()})
## Structure
${scanDirectory(process.cwd())}
`;

fs.writeFileSync('.claude/index.md', index);
console.log('Project index updated');

Результат — файл .claude/index.md который Claude читает в начале каждой сессии и мгновенно понимает структуру без дополнительных tool calls.

app/
📁 Http/
📁 Controllers/UserController, AuthController, PaymentController
📁 Middleware/
📁 Services/UserService, SubscriptionService, StripeService
📁 Models/User, Subscription, Payment
tests/
📁 Feature/AuthTest, SubscriptionTest
📁 Unit/UserServiceTest
2
ultrathink + subagents для тяжёлого reasoning

Buess использует два механизма для задач требующих глубокого анализа. Первый — слово ultrathink в промпте как сигнал для максимального использования extended thinking:

"ultrathink" — не просто слово. Это сигнал что задача требует максимального thinking-бюджета. Claude понимает этот паттерн и выделяет больше вычислений на reasoning.
// Для архитектурных решений:
"ultrathink: как нам реорганизовать систему платежей
 чтобы поддержать 5 разных провайдеров без дублирования логики?"

// Для сложного дебаггинга:
"ultrathink: почему race condition в SubscriptionService
 проявляется только под нагрузкой >100 rps?"

// Для code review:
"ultrathink: review этой реализации @app/Services/StripeService.php
 с фокусом на edge cases и потенциальные проблемы безопасности"

Второй механизм — subagents для research-фазы. Вместо одного агента который делает и исследование и реализацию — разделить роли:

# Шаг 1: Запустить research sub-агента
# Узнать Session ID текущей сессии:
/status  # показывает Session ID

# Шаг 2: Запустить headless sub-агента с контекстом основной сессии
claude --session-id $SESSION_ID \
       --model claude-opus-4-8 \
       -p "Проанализируй @app/Services/ и составь список
           всех мест где мы должны добавить транзакции БД.
           Только анализ, без изменений."

# Шаг 3: Основной агент использует результаты research
# Prompt cache переиспользуется → экономия токенов
3
Agent-Scoped Hooks — hooks прямо в агенте

Стандартные hooks в settings.json — глобальные, применяются ко всем агентам. Buess использует возможность CC 2.1+ для agent-scoped hooks: hooks прямо в frontmatter агента, который несёт их с собой.

Преимущество: каждый специализированный агент имеет только свои hooks. Агент-тестировщик запускает lint после каждого изменения. Агент-деплойщик проверяет безопасность перед Bash командами. Без взаимного влияния.

feature-developer.md — агент с собственными hooks
---
hooks:
  PreToolUse:
    - matcher: "Bash"
      command: "node ./hooks/check-safety.js"
      # Проверяет: нет rm -rf, нет git push --force, нет DROP TABLE
    - matcher: "Write|Edit"
      command: "node ./hooks/check-file-path.js"
      # Проверяет: файл не в protected/ директории

  PostToolUse:
    - matcher: "Write|Edit"
      command: "node ./hooks/run-linter.js"
      # Запускает pint/eslint сразу после каждого изменения файла
    - matcher: "Bash"
      command: "node ./hooks/log-command.js"
      # Логирует все выполненные команды в claude-audit.jsonl
---

# Агент: Feature Developer

Ты реализуешь фичу по spec в docs/superpowers/specs/.

## Порядок работы
1. Прочитать spec файл
2. Прочитать examples/ для понимания паттернов
3. Реализовать по шагам с тестами
4. Верифицировать каждый шаг перед переходом к следующему

Когда запускается этот агент — его hooks активны только в этой сессии. После завершения — удаляются автоматически. Никакого загрязнения глобальной конфигурации.

claude --agent-file ./agents/feature-developer.md \
       -p "реализуй @docs/superpowers/specs/2026-05-10-subscriptions.md"
4
Session ID passing для prompt-кеширования

Каждая сессия CC имеет уникальный Session ID. При передаче этого ID headless sub-агенту — они разделяют prompt cache, что приводит к значительной экономии токенов.

Практически важно для:

  • Длинных CLAUDE.md (1000+ строк) — кешируются один раз для всех sub-агентов
  • Больших spec-файлов которые читают несколько агентов последовательно
  • Параллельных агентов работающих над одним проектом
#!/bin/bash
# Запустить основную сессию и сохранить Session ID
SESSION_INFO=$(claude --json /status)
SESSION_ID=$(echo $SESSION_INFO | jq -r '.sessionId')

echo "Session ID: $SESSION_ID"

# Sub-агент 1: анализ безопасности (переиспользует кеш)
claude --session-id "$SESSION_ID" \
       -p "ultrathink: проверь @app/ на SQL injection уязвимости" \
       > security-report.md &

# Sub-агент 2: анализ производительности (переиспользует кеш)
claude --session-id "$SESSION_ID" \
       -p "найди N+1 запросы в @app/Http/Controllers/" \
       > performance-report.md &

# Ждём завершения обоих
wait

echo "Анализ завершён. Результаты в security-report.md и performance-report.md"
Экономия на кешировании

Без Session ID каждый sub-агент платит полную стоимость за чтение CLAUDE.md, spec-файлов и контекста. С Session ID они переиспользуют prompt cache — стоимость повторного чтения кешированного контента на 90% ниже стандартной. При 5+ sub-агентах экономия становится существенной.

5
Observability для агентов

Production-системы требуют полной видимости. Buess применяет тот же принцип к AI-агентам: каждое действие должно быть залогировано, проанализировано и измерено. Это не опционально — это необходимость для устойчивой агентной разработки.

Что логировать Зачем Инструмент
Все tool calls Аудит действий агента, отладка неожиданного поведения PostToolUse hook → JSONL файл
Стоимость каждого вызова Мониторинг расходов, обнаружение дорогих паттернов Anthropic API метаданные → dashboard
Ошибки и повторные попытки Анализ паттернов сбоев, улучшение инструкций PostToolUse hook на ошибки
Изменённые файлы Полный список что агент поменял за сессию PostToolUse Write/Edit hook
Время выполнения задач SLA для агентных операций, оптимизация PreToolUse/PostToolUse timestamps

Пример hook для полного аудита:

'use strict';
const fs = require('fs');
const path = require('path');

// Читаем данные от CC через stdin
let raw = '';
process.stdin.on('data', chunk => raw += chunk);

process.stdin.on('end', () => {
  try {
    const input = JSON.parse(raw);
    const logPath = path.join(process.cwd(), '.claude', 'claude-audit.jsonl');

    const logEntry = {
      ts: new Date().toISOString(),
      tool: input.tool_name,
      // Для файловых операций — логируем путь
      file: input.tool_input?.file_path || null,
      // Для Bash — логируем команду (первые 200 символов)
      command: input.tool_input?.command?.substring(0, 200) || null,
      // Оценка стоимости (примерная)
      estimated_tokens: JSON.stringify(input).length / 4,
    };

    fs.appendFileSync(logPath, JSON.stringify(logEntry) + '\n');
  } catch (e) {
    // Не прерываем работу агента если логирование упало
    process.stderr.write(`Logging error: ${e.message}\n`);
  }

  process.exit(0);
});

Анализ логов:

# Самые частые tool calls за сессию
cat .claude/claude-audit.jsonl | jq -r '.tool' | sort | uniq -c | sort -rn

# Все изменённые файлы
cat .claude/claude-audit.jsonl | jq -r 'select(.file != null) | .file' | sort | uniq

# Bash команды которые запускал агент
cat .claude/claude-audit.jsonl | jq -r 'select(.command != null) | .command'

# Примерная оценка стоимости сессии
cat .claude/claude-audit.jsonl | jq '[.estimated_tokens] | add'
Зачем observability это не паранойя

Когда агент работает часы над сложной задачей, без логов невозможно понять что именно пошло не так если результат плохой. Логи позволяют воспроизвести "путь мышления" агента, найти момент ошибки и исправить инструкции для следующего запуска. Это не безопасность — это инженерная дисциплина.

Полная архитектура workflow Buess

Все 5 практик работают вместе в едином workflow:

# Запуск сессии
↓ PreToolUse hook: project-indexer.js генерирует .claude/index.md
↓ Claude читает index.md — мгновенно знает структуру проекта

# Постановка сложной задачи
↓ "ultrathink: ..." — максимальный thinking budget

# Параллельный анализ через sub-агентов
↓ claude --session-id $SID -p "анализ безопасности..." &
↓ claude --session-id $SID -p "анализ производительности..." &
↓ Оба переиспользуют prompt cache → экономия токенов

# Реализация через специализированного агента
↓ claude --agent-file ./agents/feature-developer.md
↓ Agent-scoped hooks: check-safety.js, run-linter.js, log-command.js

# Каждое действие агента
↓ PostToolUse hook: log-tool-calls.js → claude-audit.jsonl
↓ Полный аудит для анализа после завершения

# Завершение задачи
↓ verification-before-completion: реальный вывод тестов
↓ Анализ .claude/claude-audit.jsonl на паттерны

Источник

Практики и подходы Eric Buess публикуются в Twitter/X @EricBuess. Он специализируется на агентной инженерии для production-систем — там где надёжность, наблюдаемость и предсказуемость критически важны. Его подход особенно актуален для команд которые хотят использовать CC не как экспериментальный инструмент, а как часть production workflow с полным контролем над каждым действием агента.