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>
This commit is contained in:
2026-05-05 17:41:11 +03:00
parent 7464ae4bc4
commit 0eb7dd1d7c
14 changed files with 632 additions and 8 deletions

View File

@@ -0,0 +1,228 @@
---
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 <path>", 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`:
```bash
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
```bash
# 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:
```bash
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:
```json
{
"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:
```bash
# 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.