meta(wiki): ingest concepts/interns-repo-read-design in claude-skills

This commit is contained in:
2026-05-05 20:04:58 +00:00
parent d9728ef2e7
commit 3400102248

View File

@@ -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.