From 340010224886346dd38e6a5bb166ee4fbb40d2d8 Mon Sep 17 00:00:00 2001 From: OpeItcLoc03 Date: Tue, 5 May 2026 20:04:58 +0000 Subject: [PATCH] meta(wiki): ingest concepts/interns-repo-read-design in claude-skills --- .wiki/concepts/interns-repo-read-design.md | 144 +++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 .wiki/concepts/interns-repo-read-design.md diff --git a/.wiki/concepts/interns-repo-read-design.md b/.wiki/concepts/interns-repo-read-design.md new file mode 100644 index 0000000..6f3bf4e --- /dev/null +++ b/.wiki/concepts/interns-repo-read-design.md @@ -0,0 +1,144 @@ +--- +date: '2026-05-05' +status: design-approved +parent: concepts/interns-design.md +source_buffer: .meeting-room/.brainstorm/repo-read.md +title: interns-repo-read-design +type: concept +ingested_at: '2026-05-05T20:04:56.490Z' +ingested_by: OpeItcLoc03@DESKTOP-NSEF0UK +source_project: .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. | + +## Сигнатура + +```python +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`) + +```python +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`) + +```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](https://github.com/yamadashy/repomix) — JS CLI, упаковывает директорию в один LLM-friendly файл. +- `using-interns/SKILL.md` — целевой файл для routing-добавки. +- `setup-interns/SKILL.md` — целевой файл для Node-check.