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

20 KiB
Raw Blame History

date, status, source_brainstorm, topic, title, type, ingested_at, ingested_by, source_project
date status source_brainstorm topic title type ingested_at ingested_by source_project
2026-05-05 design-approved .meeting-room/.brainstorm/interns.md interns interns-design concept 2026-05-05T13:58:59.608Z OpeItcLoc03@DESKTOP-NSEF0UK .meeting-room

Interns — Design Spec

Каталог специализированных «интернов» — дешёвых LLM/тулзов, которым Claude Code делегирует bulk I/O и предсказуемую генерацию, чтобы экономить Anthropic квоту. Доступ — через локальный MCP-сервер. Использование защищено per-session permission grant (зеркало project-discipline Rule 4). Каталог расширяется без переписывания скила.

Context

Triggered by Reddit thread (May 2026) и Medium-статьёй того же автора, обе в .meeting-room/.wiki/raw/research/tokens-economy/. Pattern: expensive manager (Claude) + cheap intern (DeepSeek/Kimi/Ollama). ~23× cheaper end-to-end на summarization задачах, ~125× per-call на bulk read. Без этого OP упирался в weekly Pro limit к среде.

Локальный сигнал из .meeting-room/.brainstorm/modulair-rag.md:134Marker лучше PDF, Repomix лучше код, Firecrawl лучше JS-сайты — определил выбор архитектуры (b) специализированных интернов вместо одного universal cheap-LLM.

Architecture (three layers)

┌──────────────────────────────────────────────────────────────┐
│ Layer 3 — Policy (skills)                                     │
│  using-interns       — runtime policy + permission grant      │
│  setup-interns       — one-time install/build/register        │
│  CLAUDE.md trigger:  "delegate to interns when allowed"       │
└──────────────────────────────────────────────────────────────┘
              ↑ читает / соблюдает Claude
┌──────────────────────────────────────────────────────────────┐
│ Layer 2 — Runtime (MCP server)                                │
│  .common/lib/interns-mcp/  (Python + FastMCP, stdio)          │
│   ├── interns_mcp/server.py     — MCP entry point             │
│   ├── interns_mcp/registry.py   — load catalog from config    │
│   ├── interns_mcp/client.py     — OpenAI-compatible HTTP      │
│   ├── interns_mcp/safety.py     — always-ask path matcher     │
│   └── interns_mcp/interns/      — one file per intern impl    │
│         ├── base.py                                           │
│         ├── bulk_text_read.py                                 │
│         └── transcript_distill.py                             │
│  Tools exposed:                                               │
│   mcp__interns__bulk_text_read                                │
│   mcp__interns__transcript_distill                            │
└──────────────────────────────────────────────────────────────┘
              ↑ читает on startup
┌──────────────────────────────────────────────────────────────┐
│ Layer 1 — Config (data, no code)                              │
│  .common/config/interns/config.yaml  — endpoints + tools      │
│  .common/secrets/interns.env         — API ключи (gitignored) │
└──────────────────────────────────────────────────────────────┘

Слои ортогональны. Добавить интерна = одна запись в config + один файл в interns/. Skills и setup-flow не трогаются.

MVP catalog

ID Описание Endpoint Модель Когда вызывать
bulk_text_read Прочитать N файлов и ответить на вопрос ollama_cloud deepseek-v4-flash Когда Claude собирался прочесть 3+ файлов или один >400 строк ради контекста
transcript_distill Сжать session-transcript / лог в action-list ollama_cloud deepseek-v4-flash Перед обновлением .wiki/log.md или summary документации по сессии

Оба на одном endpoint и модели — демонстрируют разделение по классу задачи, не по провайдеру. Дальнейшие интерны (PDF/web/code) — следующий релиз.

Layer 1 — Config

.common/config/interns/config.yaml:

endpoints:
  ollama_cloud:
    base_url: https://ollama.com/v1
    api_key_env: OLLAMA_CLOUD_API_KEY
    request_defaults:
      extra_body:
        reasoning: { enabled: false }      # обязательно для DeepSeek V4 — иначе max_tokens уходит в silent thinking

interns:
  bulk_text_read:
    description: "Read N files and answer a focused question. Returns concise summary."
    endpoint: ollama_cloud
    model: deepseek-v4-flash
    max_tokens: 4096
    temperature: 0.2
    system_prompt: |
      You are a careful reader. Answer ONLY what the user asks, citing
      file:line refs. Do not hallucinate file contents. If unsure, say so.

  transcript_distill:
    description: "Compress a session transcript/log into a structured action-list."
    endpoint: ollama_cloud
    model: deepseek-v4-flash
    max_tokens: 2048
    temperature: 0.1
    system_prompt: |
      Extract action items, decisions, and unresolved questions from the
      transcript. Output structured markdown sections. Be terse.

.common/secrets/interns.env (gitignored):

OLLAMA_CLOUD_API_KEY=...

Сервер на startup: загружает .env через python-dotenv → читает config.yaml → берёт ключ из os.environ[api_key_env]. Если ключа нет — setup-interns интерактивно спрашивает и пишет в .env (с preview-confirmation gate перед записью).

Layer 2 — MCP server

.common/lib/interns-mcp/:

interns-mcp/
├── pyproject.toml
├── README.md
├── interns_mcp/
│   ├── __init__.py
│   ├── server.py                — FastMCP app, tool registration
│   ├── registry.py              — load config.yaml → list of Intern objects
│   ├── client.py                — OpenAI-compatible HTTP client (per-endpoint, persistent)
│   ├── safety.py                — always-ask path matcher
│   └── interns/
│       ├── __init__.py
│       ├── base.py              — Intern protocol/dataclass
│       ├── bulk_text_read.py
│       └── transcript_distill.py
└── tests/
    ├── test_safety.py           — path matcher tests
    └── test_registry.py

Server contract:

  • На startup registry.load() проходит config, для каждого интерна делает @mcp.tool() с typed signature.
  • Tool name = <intern_id> — Claude harness сформирует mcp__interns__<id> (где interns — имя сервера в ~/.claude.json).
  • Каждый tool принимает paths: list[str], question: str, опционально max_tokens: int.
  • MCP-сервер сам читает файлы из переданных paths — Claude передаёт пути, не содержимое. Это критично для safety: сервер видит пути и применяет always-ask matcher до того как файл уйдёт в endpoint. Если бы Claude слал content, политика могла бы быть обойдена случайно (Claude прочитал .env, переслал содержимое — поздно).
  • Persistent HTTP client per-endpoint — для prefix-cache discount если endpoint его поддерживает (OpenRouter да, Ollama Cloud TBD).

Safety enforcement: safety.py проверяет каждый input path против always-ask glob-списка. Match → возвращает BlockedByPolicy объект с указанием matched-pattern; Claude получает structured ответ и сам спрашивает пользователя. Безопасность на стороне сервера — Claude может «забыть» политику в длинной сессии, MCP не забудет.

Cross-platform: Python 3.11+. Установка pip install -e .common/lib/interns-mcp/. Запуск как stdio: python -m interns_mcp.server. Без bash/PowerShell зависимостей в hot path.

Layer 3 — Skills

Два скила, по prior art (setup-context7 + using-context7, setup-projects-meta + using-projects-meta).

setup-interns (v0.1.0)

When: «set up interns», «настрой интернов», «install interns», или когда mcp__interns__* отсутствуют в сессии где они нужны.

Steps:

  1. Проверить .common/lib/interns-mcp/ существует. Если нет — инициализировать пустой через template (TBD: см. open question про source repo).
  2. pip install -e .common/lib/interns-mcp/ через активный Python interpreter.
  3. Прочитать .common/config/interns/config.yaml, для каждого endpoint.<name>.api_key_env проверить наличие в .common/secrets/interns.env. Отсутствующие — спросить интерактивно, preview перед записью, write.
  4. Зарегистрировать mcpServers.interns в ~/.claude.json:
    "interns": {
      "command": "python",
      "args": ["-m", "interns_mcp.server"]
    }
    
    Путь к Python — через shutil.which("python") или where/which в зависимости от платформы.
  5. Попросить пользователя перезапустить Claude Code.

Migration mode: detect устаревший layout (например, переезд с ~/.local/interns-mcp/ если когда-то такой был) и предложить миграцию.

using-interns (v0.1.0)

When: активируется триггером delegate to interns when allowed в CLAUDE.md. Также явные команды: «use interns», «delegate this to an intern».

Policy:

  1. Старт сессии = ask-mode. Перед первым вызовом mcp__interns__* Claude спрашивает:

    «Я бы делегировал чтение <files> интерну bulk_text_read (DeepSeek Flash, ~$0.002 за вызов). Ок?»

  2. Conversational grant.

    • «разреши интернов» / «allow interns» / «use interns» → grant до конца сессии.
    • «отзови интернов» / «revoke interns» / «делай сам» → возврат в ask-mode.
  3. Always-ask paths (даже с активным grant'ом). Полный список:

    • **/.env, **/.env.* — environment files со секретами
    • **/secrets/** — каноническая папка секретов (включая .common/secrets/)
    • **/credentials* — credentials.json и подобные
    • **/*.key — private keys любого формата
    • **/*.pem — PEM-encoded keys/certs
    • **/.ssh/** — SSH ключи
    • **/.aws/credentials, **/.aws/config — AWS credentials
    • **/.netrc, **/.npmrc, **/.pypirc — registry credentials
    • Любой путь, который Claude в текущей сессии прочитал из такого пути и теперь хочет передать интерну (transitive — нельзя обойти, прочитав файл сам и переслав содержимое).
    • Любой intern call с estimated cost >$0.10 (sanity-check, по-конфигу: tokens × price).

    Поведение: matched call → MCP возвращает BlockedByPolicy{path, pattern, reason}. Claude формулирует пользователю явный вопрос: «Файл <path> matched always-ask pattern <pattern>. Передавать интерну на endpoint <endpoint>

  4. Что НЕ делегируется (рекомендации в SKILL.md, не enforced):

    • Архитектурные / design-решения
    • Debugging — cheap model теряет тонкие баги
    • Auth / payments / PII / deletion / production data (даже если файлы не в always-ask списке)
    • Final commit messages, PR descriptions
    • Финальный текст ответа пользователю
  5. Конец сессии = reset на ask-mode. Persistent grant отвергнут как менее безопасный (зеркало Rule 4 project-discipline).

  6. Routing-подсказки (внутри SKILL.md, чтобы Claude знал когда уместно):

    • Файл >400 строк и не центральный для редактирования → bulk_text_read.
    • ≥3 файлов нужно прочитать ради контекста → bulk_text_read.
    • Перед обновлением .wiki/log.md или session-summary → transcript_distill.

Bootstrap integration

project-bootstrap v1.5.0 → v1.6.0 (MINOR — capability added):

  • assets/CLAUDE.md.template — добавить строку delegate to interns when allowed сразу после follow project discipline.
  • bootstrap-manifest.md — новые строки using-interns + setup-interns со своими version'ами.
  • Step 5 commentary — параграф с объяснением (по образцу commentary для follow project discipline).
  • Idempotent merge — существующие CLAUDE.md получат строку при следующем bootstrap (bootstrap-claude-md-merge.md уже умеет).

Cross-platform

Слой Windows Linux macOS
.common/lib/interns-mcp/ (Python 3.11+)
.common/secrets/interns.env (python-dotenv)
setup-interns install (python -m pip)
MCP registration — путь к Python where python which python which python
Always-ask matcher (pathlib.PurePath.match) POSIX-style globs работают везде

active-platform скил уже знает что показывать пользователю в каждой платформе для shell команд, никаких дублей.

Как добавить нового интерна

  1. Создать файл .common/lib/interns-mcp/interns_mcp/interns/<intern_id>.py. Шаблон:

    from .base import Intern, InternResponse
    
    class PdfRead(Intern):
        id = "pdf_read"
        description = "Extract text from PDF, including tables."
    
        def run(self, paths: list[str], question: str, **kwargs) -> InternResponse:
            # 1. Validate paths existence
            # 2. Optionally call safety.check(paths) — base.Intern может делать это в __call__
            # 3. Call external (LLM endpoint via self.client, or local subprocess like Marker)
            # 4. Return InternResponse(text=..., usage={tokens_in, tokens_out, cost_usd})
            ...
    
  2. Добавить запись в .common/config/interns/config.yaml под interns::

    pdf_read:
      description: "Extract text from PDF (tables, formulas)."
      endpoint: null                # local subprocess, нет endpoint
      # OR:
      # endpoint: ollama_cloud
      # model: deepseek-v4-flash
      max_tokens: 8192
    
  3. (Если новый endpoint) — добавить в endpoints: секцию + ключ в interns.env.

  4. Зарегистрировать tool в server.py (для MVP — explicit, см. open question про auto-discovery):

    from interns_mcp.interns.pdf_read import PdfRead
    register_tool(mcp, PdfRead())
    
  5. Restart Claude Code — новый MCP tool появится как mcp__interns__pdf_read.

  6. Routing-подсказки в using-interns/SKILL.md — добавить строку «если задача XYZ → pdf_read».

  7. (Опц.) Test в tests/test_interns_pdf_read.py. Минимум — проверка happy-path и safety-block для **/.env*.

Если интерн использует local CLI (Marker, Repomix, etc.) вместо LLM API — endpoint: null в config, и реализация в interns/<id>.py вызывает subprocess.

Open questions

  • Source repo для .common/lib/interns-mcp/. Inline в .common или отдельный repo на Gitea + git-subtree/submodule? Текущее склонение — inline (это часть .common, не самостоятельный продукт).
  • Auto-discovery интернов в registry.py (через pkgutil.iter_modules) vs explicit register_tool в server.py. Auto проще для расширения, explicit прозрачнее. Текущее склонение — explicit для MVP.
  • Cost tracking. В первом релизе — нет. Если оботрётся в реальной работе — добавим в safety.py per-call estimate из config (tokens_used × price_per_M) и блокировку >$X через always-ask механизм.
  • Sharing endpoint между meeting-room runner и interns-mcp. Сейчас .meeting-room/config/config.yaml имеет свой providers.ollama_cloud с собственным ключом; interns-mcp будет иметь свой в .common/secrets/interns.env. Дублирование. Унификация — отдельная задача.
  • Persistent prefix-cache benefit с Ollama Cloud. Документация Ollama Cloud не подтверждает prefix-cache discount явно (как делает OpenRouter). Если измерения покажут что cache не работает — рассмотреть переключение на OpenRouter как primary endpoint.

References

  • .meeting-room/.wiki/raw/research/tokens-economy/2026-05-05-i-gave-claude-code-a-$0.02call-coworker-and-stopped-hitting-pro-limits---here's-the-full-setup.md — оригинальный Reddit thread, паттерн + ~125× cost reduction цифры.
  • .meeting-room/.wiki/raw/research/tokens-economy/i-was-burning-through-claude-codes-weekly-limit-in-3-days-here-s-how-i-fixed-it.html — Medium-статья от автора Reddit-поста.
  • claude-skills/.wiki/concepts/project-discipline-design.md — Rule 4 (commit-yes-push-no per-session) — прототип permission-grant механизма для using-interns.
  • claude-skills/.wiki/concepts/skill-vs-plugin.md — обоснование bare SKILL.md.
  • claude-skills/.wiki/concepts/repo-layout.md — конвенции claude-skills repo для скилов.
  • .meeting-room/.brainstorm/modulair-rag.md:134 — selected line, повлияла на выбор архитектуры (b) специализированных интернов.