Add 3 routing-table rows for the new deterministic `grep_audit` intern per .wiki/concepts/interns-grep-audit-design.md §Layer 3: - grep_audit row — deterministic, no LLM call, zero cost - bulk_text_read vs grep_audit boundary — Q&A vs contains-check - always-ask uniform reminder — server opens file even sans LLM Consistency adds: new Overview catalog row, Tool quick reference row, prose note marking grep_audit as the catalog's first LLM-free intern. Version 0.2.2 -> 0.3.0 (MINOR — new routing capability). Closes [interns-grep-audit-skill-updates] on the .tasks board. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
224 lines
16 KiB
Markdown
224 lines
16 KiB
Markdown
---
|
||
name: using-interns
|
||
version: 0.3.0
|
||
description: Use when delegating predictable bulk reads or summarization to cheap intern LLMs via the local `interns` MCP server (`mcp__interns__bulk_text_read`, `mcp__interns__transcript_distill`, etc.) so Claude saves Anthropic quota. Activated by `delegate to interns when allowed` in CLAUDE.md or explicit phrases like "use interns", "delegate to an intern", "разреши интернов", "allow interns". **Also activates proactively when Claude is about to read 3+ files for context, read a single file >400 lines for non-edit purposes, or distill a long transcript — surface the offer "знаю, что есть интерны — заюзать?" before proceeding, even without an explicit user phrase.** Per-session permission grant mirrors `project-discipline` Rule 4: ask-mode default, conversational grant / revoke, always-ask paths for `.env` / secrets / keys / SSH / credentials even with active grant, transitive rule (Claude can't bypass by reading the file itself and forwarding content), session-end reset. Skip for architecture, debugging, auth / payments, final commit messages, or final user-facing text.
|
||
---
|
||
|
||
# Using the `interns` MCP server
|
||
|
||
## Overview
|
||
|
||
`interns` is a local stdio MCP server that exposes a catalog of cheap-LLM "interns" — DeepSeek, Kimi, Ollama-hosted models, etc. — so Claude can delegate predictable bulk I/O and summarization tasks instead of paying Anthropic quota for them. The pattern (~23× cheaper end-to-end on summarization, ~125× per-call on bulk reads) is sourced from a Reddit thread + Medium follow-up; see `.wiki/concepts/interns-design.md` for the full design and the cost numbers.
|
||
|
||
The catalog:
|
||
|
||
| Tool | What it does | When to call |
|
||
|---|---|---|
|
||
| `mcp__interns__bulk_text_read` | Reads N files end-to-end and answers a focused question with file:line citations. | Claude was about to read 3+ files or one file > 400 lines just to extract context. |
|
||
| `mcp__interns__transcript_distill` | Compresses a session transcript / log into a structured action list (decisions / open questions / next steps). | Before updating `.wiki/log.md` or producing a session summary. |
|
||
| `mcp__interns__repo_read` | Packs a directory/repo via `repomix` and answers a focused question about the codebase. | Whole-repo or whole-directory questions — architecture, "where is X used", "what does module Y do". See Routing hints for `repo_read` vs `bulk_text_read`. |
|
||
| `mcp__interns__grep_audit` | Deterministic grep matrix over N paths × M patterns. **No LLM call, no endpoint cost.** Returns ✅/❌/⚠️ table or JSON. | Contains/not-contains audits — checking a set of CLAUDE.md / SKILL.md / frontmatter files for canonical strings. See Routing hints for `grep_audit` vs `bulk_text_read`. |
|
||
|
||
LLM-backed interns currently run on Ollama Cloud (`deepseek-v4-flash`, ~$0.002 / call). `grep_audit` is the catalog's first LLM-free intern — zero cost, zero hallucination boundary. Adding a new intern is a config-only change — see `.wiki/concepts/interns-design.md` § "Как добавить нового интерна".
|
||
|
||
## Prerequisites
|
||
|
||
This skill assumes `mcp__interns__*` tools are available. If they aren't (tools missing from the session, or calls fail with a connection error), the server isn't running for this session. Trigger the **`setup-interns`** skill to `pip install -e` the runtime, write `~/.config/projects-secrets/interns.env`, and register `mcpServers.interns` in `~/.claude.json`. It's a one-time procedure with confirmation gates.
|
||
|
||
## When to use
|
||
|
||
- A read that's **bulky and not central to editing**: scanning long config files, log dumps, transcript files, generated docs — anything where Claude would burn input tokens summarizing for itself.
|
||
- A read across **3+ files** to assemble context.
|
||
- A read of **one file > 400 lines** that won't be edited.
|
||
- **Transcript / session distillation** before writing a wiki log entry, summary, or post-mortem.
|
||
- Any future intern documented in `.common/config/interns/config.yaml` (PDF extraction via Marker, repo packaging via Repomix, JS-rendered web fetches via Firecrawl, etc.) — same trigger / grant rules apply.
|
||
|
||
### Offer proactively — don't wait to be asked
|
||
|
||
When any of the conditions above match a task you're about to perform, **the offer is your first action**, not a reaction to the user mentioning interns. The user shouldn't have to remember the catalog exists — that's your job.
|
||
|
||
- **Ask-mode (default)** — surface a short offer in the user's language before proceeding:
|
||
|
||
> Знаю, что есть интерны — могу заюзать `<intern>` для `<task>`?
|
||
|
||
English equivalent:
|
||
|
||
> Interns can handle this — want me to delegate `<task>` to `<intern>`?
|
||
|
||
Keep it short. Don't pre-quote cost / model / tool name in the offer — those are in the catalog, the user can ask if curious. Verbose ask = friction = user defaults to "just do it yourself" even when delegation was the better move.
|
||
|
||
- **Grant active** — skip the offer entirely. Delegate with a one-line FYI:
|
||
|
||
> Делегирую `<intern>` для `<task>` (`<N> файлов` / `<N> строк`).
|
||
|
||
- **Recognition heuristics for "I'm about to do an intern-shaped task":** mid-task, before issuing N `Read`s in a batch, ask yourself: would this become 3+ Read calls? Is the file I'm about to open >400 lines and I won't edit it? Am I reading a transcript to summarize, not to navigate? Any yes → offer.
|
||
|
||
This is the change that actually delivers the savings — the catalog is useless if Claude only remembers it when prompted.
|
||
|
||
## When NOT to use
|
||
|
||
- **Architecture / design decisions.** Cheap models miss subtle trade-offs.
|
||
- **Debugging.** Cheap models hallucinate in ways that turn a 5-minute fix into a 1-hour wild goose chase.
|
||
- **Auth / payments / PII / production data / deletion.** Recommendation, not enforced — but obvious.
|
||
- **Final commit messages, PR descriptions, user-facing answers.** The task explicitly delegated *to* Claude. Don't sub-delegate the deliverable.
|
||
- **Anything that fits into Claude's own working context cheaply.** A 50-line file to skim is not a delegation candidate; it's just a Read.
|
||
|
||
## Per-session permission grant (mirrors `project-discipline` Rule 4)
|
||
|
||
The grant mechanism is identical in shape to the push-grant in `project-discipline`. Reuse the same vocabulary so the user doesn't have to learn two policies.
|
||
|
||
### Default — ask-mode
|
||
|
||
Every session starts in ask-mode. Before the first `mcp__interns__*` call, ask:
|
||
|
||
> Я бы делегировал чтение `<files>` интерну `bulk_text_read` (DeepSeek Flash via Ollama Cloud, ~$0.002 за вызов). Ок?
|
||
|
||
(or its English equivalent if the user is communicating in English) and wait for explicit `yes` / `да` / `go` / `поехали`. Without confirmation — don't call.
|
||
|
||
### Conversational grant
|
||
|
||
When the user says any of:
|
||
|
||
- "разреши интернов" / "разреши интерна" / "разреши делегировать"
|
||
- "allow interns" / "use interns freely" / "go ahead with interns"
|
||
|
||
— grant the right to call `mcp__interns__*` without further confirmation **for the rest of the session**, subject to always-ask paths below. Acknowledge the grant in one short line ("ок, делегирую интернам без подтверждения, кроме secrets-путей" / "got it, free delegation except secrets").
|
||
|
||
### Conversational revoke
|
||
|
||
When the user says any of:
|
||
|
||
- "отзови интернов" / "снова спрашивай" / "делай сам"
|
||
- "revoke interns" / "stop using interns" / "ask me again every time"
|
||
|
||
— return to ask-mode for the rest of the session. Acknowledge in one short line.
|
||
|
||
### Session-end reset
|
||
|
||
The next session starts in ask-mode regardless of prior grants. Same reasoning as `project-discipline` Rule 4: a grant is given for the current context (user nearby, attention available), and should not survive a context switch.
|
||
|
||
### Always-ask paths (even with active grant)
|
||
|
||
These never go to an intern silently, even when delegation is granted:
|
||
|
||
- `**/.env`, `**/.env.*`
|
||
- `**/secrets/**`, `**/projects-secrets/**` (including `~/.config/projects-secrets/`, `~/.config/projects-mcp/`)
|
||
- `**/credentials*`, `**/credentials.json`
|
||
- `**/*.key`, `**/*.pem`
|
||
- `**/.ssh/**`
|
||
- `**/.aws/credentials`, `**/.aws/config`
|
||
- `**/.netrc`, `**/.npmrc`, `**/.pypirc`
|
||
|
||
The `interns` MCP server enforces this server-side: matched paths return `BlockedByPolicy{path, pattern, reason}` instead of going out to the endpoint. Claude's job: **don't try to bypass** by reading the file with the local `Read` tool and forwarding the content as a string argument. The transitive rule applies — once a file matched, its content stays out of every intern call for the rest of the session unless the user explicitly grants per-path.
|
||
|
||
When a path is blocked, ask the user explicitly:
|
||
|
||
> Файл `<path>` matched always-ask pattern `<pattern>` (reason: `<reason>`). Передавать интерну на endpoint `<endpoint>` несмотря на это?
|
||
|
||
Wait for an explicit per-path "yes". Don't generalize the answer to other paths in the same call.
|
||
|
||
### Cost-based always-ask
|
||
|
||
Any call with estimated cost > $0.10 (per the `tokens × price_per_M` config in `.common/config/interns/config.yaml`) goes to ask-mode regardless of grant state. Sanity bound — catches a misrouted huge-payload request before it bills.
|
||
|
||
## Routing hints (when to pick which intern)
|
||
|
||
| Situation | Intern |
|
||
|---|---|
|
||
| File > 400 lines, not editing it | `bulk_text_read` |
|
||
| Need to read 3+ files for context | `bulk_text_read` |
|
||
| Whole-repo or whole-directory question (architecture, "where is X used", "what does module Y do") | `repo_read` |
|
||
| `bulk_text_read` vs `repo_read` | Use `bulk_text_read` when file paths are known and explicit. Use `repo_read` when you need a whole directory without cherry-picking files — repomix packs everything under the given paths. |
|
||
| Don't delegate editing or debugging a specific file to `repo_read` | Read the file yourself. `repo_read` is for comprehension, not modification. |
|
||
| Updating `.wiki/log.md` or session-summary doc | `transcript_distill` |
|
||
| Compressing a long brainstorm transcript before quoting in a design doc | `transcript_distill` |
|
||
| Audit N paths × M patterns (contains/not-contains matrix — checking CLAUDE.md / SKILL.md / frontmatter for canonical strings) | `grep_audit` — deterministic, no LLM call, zero cost, zero hallucination boundary |
|
||
| `bulk_text_read` vs `grep_audit` | `bulk_text_read` is Q&A with an LLM over files; `grep_audit` is deterministic contains/not-contains. Semantic match (paraphrase, intent) → `bulk_text_read` with a question, not `grep_audit`. |
|
||
| Always-ask paths apply uniformly to `grep_audit` | The server still opens the file even without an LLM call — no special "safe intern" carve-out. Same `.env` / secrets / keys / SSH gate as the LLM-backed interns. |
|
||
| (Future interns in `config.yaml`) | per the description in the catalog |
|
||
|
||
## Workflow
|
||
|
||
```
|
||
1. Identify the candidate task (read-heavy, bulk, predictable).
|
||
2. Pick the intern from the routing table.
|
||
3. Check grant state:
|
||
• ask-mode → ask before calling
|
||
• granted → check always-ask paths; if any matched, ask per-path
|
||
4. Call the intern with `paths` (list of file paths — the server reads them)
|
||
and `question` (focused, specific).
|
||
5. Cite the response (file:line refs come from the intern's reply).
|
||
```
|
||
|
||
Don't pass file *contents* as arguments — only paths. The MCP server reads and applies the always-ask matcher before any path content reaches an endpoint. If you forward content yourself, the gate is bypassed and the user can't trust the policy.
|
||
|
||
## Tool quick reference
|
||
|
||
| Tool | Required args | Optional | Purpose |
|
||
|---|---|---|---|
|
||
| `mcp__interns__bulk_text_read` | `paths: list[str]`, `question: str` | `max_tokens: int` | Read N files end-to-end, answer the question with citations. |
|
||
| `mcp__interns__repo_read` | `paths: list[str]`, `question: str` | `compress: bool`, `max_tokens: int` | Pack directory/repo via repomix, answer the question. Use `compress=True` for large codebases (lossy: strips comments/whitespace). |
|
||
| `mcp__interns__transcript_distill` | `paths: list[str]`, `question: str` | `max_tokens: int` | Distill transcript / log into structured action list. |
|
||
| `mcp__interns__grep_audit` | `paths: list[str]`, `patterns: list[str \| dict]` | `output: "table" \| "json"` (default `"table"`), `case_sensitive: bool` (default `True`) | Deterministic grep matrix over N paths × M patterns. No LLM call. Returns ✅/❌/⚠️ table or JSON. `patterns` are substring by default; pass `{pattern, name, regex: true}` for named regex columns. |
|
||
|
||
(Future interns expose tools at `mcp__interns__<intern_id>` as the catalog grows.)
|
||
|
||
## Examples
|
||
|
||
### Read-bulk delegation
|
||
|
||
User: "summarize what these four config files do for the build pipeline."
|
||
|
||
```
|
||
1. Routing → bulk_text_read (4 files, context only).
|
||
2. Grant state → ask-mode (session start).
|
||
3. Ask: "Bulk-read these 4 files via bulk_text_read (~$0.002)? Ок?"
|
||
4. User: "ok"
|
||
5. Call mcp__interns__bulk_text_read
|
||
paths: ["build/config.ts", "build/plugins.ts", "build/env.ts", "build/output.ts"]
|
||
question: "What does each file contribute to the build pipeline? Cite file:line."
|
||
6. Cite the response. Done.
|
||
```
|
||
|
||
### Always-ask path triggered
|
||
|
||
User: "scan all `.env*` files in the repo and tell me which keys are duplicated."
|
||
|
||
```
|
||
1. Routing → bulk_text_read.
|
||
2. Grant state → granted (user said "allow interns" earlier).
|
||
3. Path matcher → every input matches `**/.env`. Server returns BlockedByPolicy.
|
||
4. Ask user: "These are .env files (always-ask). Pass them to bulk_text_read despite the secrets exposure?"
|
||
5. Wait for explicit per-path yes/no.
|
||
```
|
||
|
||
### Transcript distill
|
||
|
||
User: "compress this brainstorm transcript into action items before I ingest it into the wiki."
|
||
|
||
```
|
||
1. Routing → transcript_distill.
|
||
2. Call mcp__interns__transcript_distill
|
||
paths: [".meeting-room/.brainstorm/foo.md"]
|
||
question: "Extract decisions, open questions, and next steps. Output structured markdown."
|
||
3. Quote the result in the wiki ingest commit.
|
||
```
|
||
|
||
## Common mistakes
|
||
|
||
| Mistake | Fix |
|
||
|---|---|
|
||
| Calling an intern in ask-mode without asking first | Ask before the first call every session, even for trivial reads. |
|
||
| Forwarding file *content* instead of *path* | Pass paths. The server reads. The matcher only sees paths. |
|
||
| Trying to bypass always-ask by reading the file with `Read` and pasting content | Transitive rule — that path stays out of intern calls for the session unless user says otherwise per-path. |
|
||
| Sub-delegating final deliverables (commit messages, user-facing answers) | Those are Claude's job. Interns are for predictable bulk I/O, not for the answer that ships. |
|
||
| Using an intern for debugging | Cheap models miss subtle bugs. Pay the Anthropic call for debugging — the savings aren't worth a wrong fix. |
|
||
| Persistent grant across sessions | The next session resets to ask-mode. By design — same as project-discipline Rule 4. |
|
||
|
||
## Red flags
|
||
|
||
- "I'll just paste the content as a string arg" → no. The matcher only sees paths. If you're tempted to bypass it, you're about to leak a secret.
|
||
- "This grant should survive the session" → no. The next session asks again. The grant is bound to the current context where the user is paying attention.
|
||
- "It's just a small file, why ask?" → small files don't need an intern. Read them yourself. The ask is *because* the call goes to a third-party endpoint, not because of size.
|
||
- "Estimated cost is fine, $0.08 < $0.10" → still ask if the call is novel or the file set is unfamiliar. The cost gate is a hard ceiling, not the only signal.
|