Files
claude-skills/skills/setup-interns/SKILL.md
vitya 0eb7dd1d7c feat(interns-skills-mvp): ship setup-interns + using-interns v0.1.0; project-bootstrap 1.5.0 -> 1.6.0
setup-interns (v0.1.0) — 8-phase install of the local `interns` MCP server:
detect `.common/lib/interns-mcp/` source, `pip install -e`, write
`.common/secrets/interns.env` with endpoint API keys (gitignored), register
`mcpServers.interns` in `~/.claude.json` with absolute Python interpreter
path + `cwd` so the runtime resolves config relative to project root.
Mirrors setup-projects-meta / setup-context7 confirmation-gate shape.
Description 899 chars (under the 900 budget per
feedback_skill_description_length_limit).

using-interns (v0.1.0) — runtime policy for `mcp__interns__*`. Per-session
permission grant mirrors project-discipline Rule 4: ask-mode default,
conversational grant ("разреши интернов" / "allow interns"), conversational
revoke, always-ask paths for `**/.env`, `**/secrets/**`, `**/*.key`,
`**/.ssh/**`, `**/.aws/credentials` etc with transitive rule (Claude can't
bypass by reading the file with the local Read tool and forwarding content),
cost-cap >$0.10 always asks, session-end automatic reset. Routing hints for
`bulk_text_read` (3+ files or one file >400 lines) and `transcript_distill`
(before .wiki/log.md updates / session summaries). Description 814 chars.

project-bootstrap (1.5.0 -> 1.6.0, MINOR — capability added):
* assets/CLAUDE.md.template: insert `delegate to interns when allowed`
  between `follow project discipline` and `we're on Windows`.
* SKILL.md Step 5: same insertion in inline template + new commentary
  paragraph explaining the trigger, no-op semantics, install pointer.
* SKILL.md Step 5.5: bootstrap-manifest table extended with
  `setup-interns`, `using-interns`, `project-discipline` rows.
* README.md: Workflow Step 5.5 description + See also section both pick up
  the new skills.

Root CLAUDE.md dogfood: `delegate to interns when allowed` line added.
.wiki/log.md decision entry. .tasks/STATUS.md task moved to 🟢 done.
.tasks/interns-skills-mvp.md per-task file with goal / key-files /
decisions log / open questions.

Build + install verified: `dist/{setup-interns,using-interns,
project-bootstrap}.skill` rebuilt; `bash scripts/install.sh ...` succeeded;
harness skill listing shows full descriptions for all three (no H1
fallback) — confirms the description budget held.

Versioning per project-discipline Rule 3:
* setup-interns: 0.1.0 (first edit of unversioned artifact, MAJOR=0).
* using-interns: 0.1.0 (first edit of unversioned artifact, MAJOR=0).
* project-bootstrap: 1.5.0 -> 1.6.0 (MINOR — adds capability without
  breaking existing CLAUDE.md merge or manifest consumers).

Server runtime itself (`.common/lib/interns-mcp/`) is out of scope for this
task — the skills land lifecycle, policy, and bootstrap integration so any
machine where the MCP server is later installed already has Claude's
policy in place.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 17:41:11 +03:00

13 KiB

name: setup-interns version: 0.1.0 description: Installs and configures the local interns MCP server — a FastMCP stdio app at <project-root>/.common/lib/interns-mcp/ that delegates bulk reads, transcript distillation, and other predictable I/O to cheap intern LLMs (DeepSeek / Kimi / Ollama) so Claude saves Anthropic quota. Procedure: detect the server source, pip install -e it, write .common/secrets/interns.env with the endpoint API keys, register mcpServers.interns in ~/.claude.json. Use this skill when the user says "install interns", "set up interns", "configure interns", "настрой интернов", "установи интернов", "interns не работает", "interns isn't working", or whenever the mcp__interns__* tools are missing in a session that needs delegation. Cross-platform — Windows / Linux / macOS. Mutates user-level config and writes secrets; pauses for confirmation before every write.

setup-interns

One-time skill that gets the local interns MCP server running with the user's endpoint API keys and a registered mcpServers.interns entry in ~/.claude.json. Stops at confirmation gates because the procedure runs pip install, writes a secret-bearing .env file, and edits user-level config.

Reference: full design lives in this repo at .wiki/concepts/interns-design.md (Layer 1/2/3 architecture, MVP catalog, always-ask paths, routing hints).

When to use

  • User explicitly asks: install / set up / configure interns.
  • A using-interns-driven task fails because mcp__interns__* tools aren't available in the session.
  • New machine in the user's multi-machine fleet — install once per machine that wants delegation.
  • Migrating a stale install (endpoint key rotated, server source moved, broken dist/ artifact) — same procedure, Phase 1 detects what's already in place.

Out of scope

  • Building or scaffolding the .common/lib/interns-mcp/ source tree itself. The skill expects the source already in place per the inline .common/ convention from the design (or a future Gitea repo when that branch lands). If the source is absent, Phase 1 stops with a clear message — initializing a fresh runtime is a separate task.
  • Issuing or rotating endpoint API keys (Ollama Cloud, OpenRouter, etc.). The skill uses keys the user already has; if there is none, it points at the provider's settings page and stops.
  • Running interns-mcp itself — the Claude Code harness spawns it on session start.
  • Authoring new interns or editing .common/config/interns/config.yaml — that's a content task, not a setup task.
  • Any other MCP server.

Hard rule: don't auto-mutate config

The procedure runs pip install, writes .common/secrets/interns.env (carries endpoint API keys), and edits ~/.claude.json. Always pause for explicit confirmation between Phase 1 (discovery, read-only) and Phase 2 (plan), and again before Phase 3 (backup + writes). A trigger phrase grants permission to inspect, not to install or write secrets.

Procedure

Phase 0 — Environment sanity

  • Confirm Claude Code is the current harness (need mcpServers registration in ~/.claude.json).
  • Confirm python ≥ 3.11 and pip are on PATH. Report the resolved interpreter path (python -c "import sys; print(sys.executable)"); the skill will pin this exact path in the MCP registration so a later python shadowed by another env doesn't silently take over.
  • Confirm network reachability to the configured endpoints (default: https://ollama.com/v1). On HTTP 401 / 403 later, the API key is dead — stop and ask for a new one.
  • Pick paths: <project-root>/.common/lib/interns-mcp/ (source), <project-root>/.common/config/interns/config.yaml (catalog), <project-root>/.common/secrets/interns.env (keys, gitignored), ~/.claude.json (MCP registration). POSIX-style paths resolve correctly under git-bash on Windows.

Phase 1 — Discovery (read-only)

Search, in order. Report only "found at ", never echo key values.

Server source. Check whether <project-root>/.common/lib/interns-mcp/pyproject.toml exists. If absent, stop — the runtime source must be in place before this skill runs. Report:

.common/lib/interns-mcp/ not found.
This skill expects the inline interns-mcp source per the
.common/ layout (see .wiki/concepts/interns-design.md). Initialize
the runtime first, then re-run setup-interns.

Build artifact. Run python -c "import interns_mcp" 2>&1 against the candidate interpreter. If it fails with ModuleNotFoundError, Phase 4 will run pip install -e .common/lib/interns-mcp/. If it succeeds, capture the installed location and skip the install in Phase 4.

Config catalog. Read <project-root>/.common/config/interns/config.yaml. Extract the unique set of endpoints.<name>.api_key_env values — these are the env var names the runtime expects to find. Capture for Phase 2.

Existing endpoint keys. Look in priority order, per api_key_env name from the config:

  1. <project-root>/.common/secrets/interns.env (<NAME>=... lines).
  2. Process env (os.environ[<NAME>]).
  3. ~/.config/projects-mcp/auth.toml — only if the user has explicitly noted the key is shared with another local MCP server (rare).

The first hit wins per key. Never echo key values in chat.

MCP registration. Read ~/.claude.json and check mcpServers.interns. Note the command and args. If args point at a stale interpreter, Phase 6 will fix it.

Gitignore sanity. Check .gitignore (project root). If .common/secrets/ (or .common/secrets/*.env) is not listed, flag for Phase 2 — the skill will offer to add it before writing the file.

Phase 2 — Plan + confirm

Present a single-block plan to the user:

Source:        <found at .common/lib/interns-mcp/ | NOT FOUND — STOP>
Module:        <interns_mcp importable | will pip install -e>
Config:        <found at .common/config/interns/config.yaml> — endpoints: <names>
Missing keys:  <list of <NAME> not yet present in interns.env | none>
Gitignore:     <covers .common/secrets/ | will add ".common/secrets/*.env">
MCP entry:     <present in ~/.claude.json | will add | will fix interpreter path>
Backups:       ~/.claude.json.bak-<ts>, .common/secrets/interns.env.bak-<ts> (if exists)

Wait for explicit confirmation ("ok", "go", "поехали"). Anything else → stop.

For each missing key, ask: "Paste a value for <NAME> (endpoint: <endpoint_name> — provider settings page: <url-from-config-or-known-list>), or skip and we'll leave the entry blank for you to fill later." Don't proceed past Phase 2 without resolving every required key — the runtime won't start with a missing API key.

Phase 3 — Backup

Copy each file we will modify to <file>.bak-YYYYMMDD-HHMMSS:

TS=$(date +%Y%m%d-%H%M%S)
[ -f ~/.claude.json ] && cp ~/.claude.json ~/.claude.json.bak-$TS
[ -f .common/secrets/interns.env ] && cp .common/secrets/interns.env .common/secrets/interns.env.bak-$TS

Confirm both backups exist (when their source existed) before any further edit.

Phase 4 — Install Python module

# from project root
python -m pip install -e .common/lib/interns-mcp/

Capture the resolved python from Phase 0; use the same interpreter for both pip install and the later MCP command: field. Verify post-install:

python -c "import interns_mcp; print(interns_mcp.__file__)"

If import fails — abort. Ask the user to paste the pip install output so the failure mode is visible.

Phase 5 — Write interns.env + gitignore

If Phase 1 flagged a missing .gitignore rule, append it first:

# interns endpoint API keys
.common/secrets/*.env

Then write .common/secrets/interns.env. Per-key behavior:

  • Existing key in the file with a non-empty value — leave it alone.
  • Missing key — append <NAME>=<value-from-Phase-2> if the user pasted one, or <NAME>= (blank) if the user skipped. A blank entry will fail at runtime with a clear KeyError; that's acceptable for the "I'll fill it later" path.

Permissions: on Linux / macOS run chmod 600 .common/secrets/interns.env. On Windows the default ACL is per-user, no extra step.

Phase 6 — Register in ~/.claude.json

Edit ~/.claude.json. Add or update the mcpServers.interns block:

{
  "mcpServers": {
    "interns": {
      "command": "<ABSOLUTE_PATH_TO_PYTHON>",
      "args": ["-m", "interns_mcp.server"],
      "cwd": "<ABSOLUTE_PATH_TO_PROJECT_ROOT>"
    }
  }
}

cwd is set so the runtime resolves .common/config/interns/config.yaml and .common/secrets/interns.env relative to project root regardless of where Claude Code was launched.

Absolute interpreter path comes from Phase 0 (sys.executable). Forward slashes work in JSON on Windows without escaping.

After each edit, validate JSON:

# Windows (git-bash)
powershell.exe -NoProfile -c "Get-Content '<file>' -Raw | ConvertFrom-Json | Out-Null"
# Linux / macOS
jq empty <file>
# fallback
python -c "import json; json.load(open('<file>'))"

If validation fails → restore from .bak-* and abort.

Phase 7 — Smoke test (best-effort)

Best-effort: ask the user to call mcp__interns__bulk_text_read against a tiny benign input (e.g. read this file's Phase 7 section, ask "what is this section about?"). A response that is structurally valid (text + usage) means the server is reachable.

Important caveat to relay to the user: in the same session that just ran setup, the active MCP connection was bound at session start. So a passing in-session smoke test only proves "an interns server is alive" — not "the registration we just wrote is what's serving it". The real test is after Claude Code restart.

If mcp__interns__* tools aren't registered in this session at all, skip the smoke test and rely on Phase 8.

Phase 8 — Restart guidance + final report

Tell the user:

✅ Setup complete. Restart Claude Code so the new mcpServers.interns
   registration binds to a fresh stdio session.

After restart:
  • mcp__interns__* tools serve from <python> -m interns_mcp.server
  • Endpoint keys live in .common/secrets/interns.env (gitignored)
  • Config catalog at .common/config/interns/config.yaml
  • Backups saved at ~/.claude.json.bak-<ts> (and interns.env.bak-<ts>
    if it existed before)

Runtime policy lives in `using-interns`. CLAUDE.md trigger:
  delegate to interns when allowed
project-bootstrap 1.6.0+ adds it to new projects automatically.

If something breaks after restart:
  • Restore from .bak-* and tell me — we'll roll back together.

Rollback procedure

If a problem surfaces (now or after restart):

  1. Stop. Don't try to fix forward.
  2. Find the most recent .bak-YYYYMMDD-HHMMSS next to ~/.claude.json and .common/secrets/interns.env.
  3. cp <file>.bak-<ts> <file> for each.
  4. Optional: pip uninstall interns-mcp if you want to remove the editable install.
  5. Restart Claude Code.
  6. Confirm mcp__interns__* is gone (or back to its pre-existing version).
  7. Report what went wrong so we can fix the procedure.

Cross-platform notes

The procedure is platform-agnostic. Only auxiliary tooling differs:

JSON validate Backup Permissions on .env
Windows (git-bash) powershell.exe -NoProfile -c "Get-Content '<f>' -Raw | ConvertFrom-Json | Out-Null" cp per-user ACL by default
Linux jq empty <f> (or python -c "import json; json.load(open('<f>'))") cp chmod 600
macOS same as Linux cp chmod 600

POSIX-style paths (.common/..., ~/.claude.json) work on all three.

Common mistakes

  • Skipping Phase 1. "User just said 'install interns' — let's go." No — find existing source / module / keys first; clobbering an existing .env over a working one loses keys you can't recover.
  • Echoing endpoint keys. They're secrets. Edit / Write tool calls inevitably contain them (that's how they land in .env), but no chat output should.
  • Pinning python instead of <sys.executable>. A bare python in the MCP command: resolves to whatever interpreter is first on PATH at session start — often a different env without the interns_mcp module. Always use the absolute interpreter path captured in Phase 0.
  • Forgetting cwd:. Without it the runtime can't find .common/config/interns/config.yaml and bombs at startup with a config-not-found error that looks like a Claude Code bug.
  • Writing .env with 0644 perms on Linux/macOS. Token leak. Always chmod 600 after write.
  • Missing the gitignore rule. Tokens commit to the repo on the next git add .. Always check .gitignore covers .common/secrets/*.env before writing — Phase 5 does it but it's worth double-checking.
  • Treating in-session smoke test as proof. Same as the context7 / projects-meta caveat — the active MCP connection was bound at session start. Real verification happens after restart.
  • Auto-running on every "use interns". This skill is intrusive. Trigger only on explicit "install / set up / configure interns", or when MCP tools are missing and the user is blocked.