Files
claude-skills/.wiki/concepts/interns-repo-read-design.md

9.1 KiB
Raw Blame History

date, status, parent, source_buffer, title, type, ingested_at, ingested_by, source_project
date status parent source_buffer title type ingested_at ingested_by source_project
2026-05-05 design-approved concepts/interns-design.md .meeting-room/.brainstorm/repo-read.md interns-repo-read-design concept 2026-05-05T20:04:56.490Z OpeItcLoc03@DESKTOP-NSEF0UK .meeting-room

Interns — repo_read intern (v0.1.0)

Расширение каталога interns-mcp MVP: добавляет интерн repo_read, специализированный на «прочитай эту директорию/репо и ответь на вопрос». Реализуется поверх существующей трёхслойной архитектуры (config / MCP server / skills) без изменений в архитектуре, только новый tool + routing-добавка в using-interns.

Context

Из исходного research line: «Repomix лучше код». Интерн оборачивает repomix CLI + cheap LLM (deepseek-v4-flash) в один MCP tool, чтобы Claude делегировал понимание целой кодовой базы дешёвой модели вместо того чтобы прочитать репо своим Read'ом и сжечь Anthropic-квоту.

Это первый tool-wrapping интерн (subprocess + LLM-call в одной операции) — паттерн под будущие PDF (Marker) и JS-web (Firecrawl) интерны.

Decisions

# Решение Аргумент
1 Шейп — композитный repo_read(paths, question) → answer Симметрия с bulk_text_read(paths, question) → answer. Pure pack не экономит квоту — Claude всё равно читает результат.
2 Tool name repo_read (не repo_qa, не code_read) Симметрия с bulk_text_read (тоже семантически Q&A, но _read). Не code_read — repomix именно про директорию целиком, оставляем code_read под будущий grep+cheap-LLM интерн.
3 Overflow при превышении контекста — hard fail с подсказкой YAGNI. Без авто-compress / map-reduce / smart-selection. Параметр compress: bool = False явный, user-controlled.
4 Runtime — npx repomix@latest Zero-config: setup-interns только проверяет node в PATH. Всегда свежая версия. Первый запуск 5-10s (npm cache populate), потом instant. Pin'ить версию — позже, если будут регрессии.
5 Safety — два слоя: input matcher + transitive --ignore Always-ask matcher проверяет input paths (как у остальных interns). Дополнительно: safety.always_ask_globs() транслируется в флаги --ignore для repomix subprocess'а. Repomix walks recursively, нельзя надеяться что .gitignore юзера полный. Защита on-server.
6 Без include/ignore параметров от Claude YAGNI: исключение через узкие paths + .gitignore + always-ask. Если упрёмся — добавим в v0.2.0.

Сигнатура

repo_read(
    paths: list[str],          # директории и/или файлы — targets для repomix
    question: str,             # вопрос
    compress: bool = False,    # repomix --compress (lossy: убирает комменты/whitespace)
) -> InternResponse

InternResponse = {text: str, usage: {tokens_in, tokens_out, cost_usd, packed_files: int, packed_tokens: int}}

При overflow: вместо InternResponse возвращается BudgetExceededError{tokens, limit, top_files: [...], hint} — Claude получает structured ответ и переформулирует (узкие paths или compress=True).

Реализация (interns_mcp/interns/repo_read.py)

class RepoRead(Intern):
    id = "repo_read"

    def run(self, paths, question, compress=False):
        safety.check_paths(paths)                       # raise if always-ask
        ignore_globs = safety.always_ask_globs()        # transitive guard

        with tempfile.NamedTemporaryFile(suffix=".xml", delete=False) as packed:
            args = ["npx", "repomix@latest", *paths,
                    "--output", packed.name, "--style", "xml"]
            if compress:
                args.append("--compress")
            for glob in ignore_globs:
                args += ["--ignore", glob]
            subprocess.run(args, check=True, timeout=120)
            packed_text = Path(packed.name).read_text()

        tokens = count_tokens(packed_text, model=self.config.model)
        if tokens > self.config.context_budget:
            return BudgetExceededError(
                tokens=tokens,
                limit=self.config.context_budget,
                top_files=top_files_by_size(packed_text, n=5),
                hint="use compress=True or narrow paths",
            )

        return self.client.complete(
            system=self.config.system_prompt,
            user=f"# Packed repo\n\n{packed_text}\n\n# Question\n\n{question}",
            max_tokens=self.config.max_tokens,
        )

Layer 1 — config (.common/config/interns/config.yaml)

interns:
  repo_read:
    description: "Pack a repo/directory via repomix and answer a focused question via cheap LLM."
    endpoint: ollama_cloud
    model: deepseek-v4-flash
    max_tokens: 4096
    temperature: 0.2
    context_budget: 120000        # input-token cap before BudgetExceededError
    system_prompt: |
      You are reading a packed code repository. Answer ONLY what the user asks,
      citing file:line refs from the packed structure. Do not hallucinate file
      contents. If the answer requires files outside the pack, say so explicitly.

Layer 3 — skill update

using-interns/SKILL.md, секция Routing-подсказки — добавить:

  • Вопрос про целое репо/директорию (архитектура, «где используется X», «что делает модуль Y», обзор кодбазы) и нужно прочесть >5 файлов кода → repo_read.
  • bulk_text_read vs repo_read: первый — пути известны и явные; второй — нужна целая директория без явного выбора файлов.
  • Не делегировать repo_read для редактирования или отладки конкретного файла — читать файл сам.

Setup-side change

setup-interns/SKILL.md — добавить runtime check:

  1. shutil.which("node") — если нет, instruct: install Node.js 20+, retry.
  2. (Опц.) Pre-warm: npx --yes repomix@latest --version чтобы первый реальный вызов был быстрым.

Bump setup-interns 0.1.0 → 0.2.0 (MINOR — capability added).

Cross-platform

Слой Windows Linux macOS
npx repomix@latest OK через node from PATH OK OK
tempfile.NamedTemporaryFile OK OK OK
Always-ask globs (PurePath.match) OK POSIX-style работают везде OK OK
subprocess.run timeout OK OK OK

Action items

  • .common/lib/interns-mcp: реализовать interns_mcp/interns/repo_read.py, зарегистрировать в server.py. Тесты: happy-path, safety-block (paths=[".env"]), budget-exceeded. Patch-bump interns-mcp.
  • .common/config/interns/config.yaml: добавить запись repo_read.
  • claude-skills/using-interns: добавить routing-подсказки в SKILL.md. Bump MINOR.
  • claude-skills/setup-interns: добавить Node-check + (опц.) pre-warm. Bump MINOR.

Open questions

  • Реальный context window deepseek-v4-flash на Ollama Cloud — проверить эмпирически после первого боевого вызова, скорректировать context_budget.
  • Когда появится 2-3-й tool-wrapping интерн (PDF/web) — выделить общий helper interns_mcp/tool_wrapper.py для пары (subprocess + safety-translation + budget-check). Сейчас inline в repo_read.py.
  • Cost-cap >$0.10 (упомянут в parent spec как always-ask trigger) — не реализован. Если появится несколько tool-wrapping interns с разной стоимостью — добавим safety.check_cost(estimated) рядом с check_paths.

References

  • concepts/interns-design.md — parent design (архитектура interns-mcp, "How to add an intern" recipe, action items).
  • Repomix — JS CLI, упаковывает директорию в один LLM-friendly файл.
  • using-interns/SKILL.md — целевой файл для routing-добавки.
  • setup-interns/SKILL.md — целевой файл для Node-check.